Skip to content

Commit

Permalink
[#813] DB migration validator
Browse files Browse the repository at this point in the history
Script that inspects the databases and compare
via the Django ORM.
  • Loading branch information
kardan committed Oct 28, 2014
1 parent d6439a3 commit 93821a3
Show file tree
Hide file tree
Showing 5 changed files with 592 additions and 158 deletions.
181 changes: 181 additions & 0 deletions akvo/rsr/static/rsr/v3/js/src/react-my-details.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/** @jsx React.DOM */

var Modal = ReactBootstrap.Modal;
var ModalTrigger = ReactBootstrap.ModalTrigger;
var Button = ReactBootstrap.Button;
var Table = ReactBootstrap.Table;
var Input = ReactBootstrap.Input;

var ResponseModal = React.createClass({displayName: 'ResponseModal',
render: function () {
return this.transferPropsTo(
Modal({title: this.props.title},
React.DOM.div({className: "modal-body"}, this.props.response),
React.DOM.div({className: "modal-footer"}, Button({onClick: this.props.onRequestHide}, "Close"))
)
);
}
});

var Employment = React.createClass({displayName: 'Employment',
getInitialState: function() {
return {visible: true};
},

onDelete: function() {
this.setState({visible: false});
},

render: function() {
return this.state.visible
? React.DOM.li(null, this.props.employment.organisation_full.long_name, " - ", React.DOM.i(null, this.props.employment.job_title, " ", this.props.employment.country_full.name))
: React.DOM.span(null);
}
});

var EmploymentList = React.createClass({displayName: 'EmploymentList',
render: function () {
var employments = this.props.employments.map(function(employment) {
return (
Employment({employment: employment})
)
});
return (
React.DOM.ul(null, employments)
);
}
});

var OrganisationInput = React.createClass({displayName: 'OrganisationInput',
render: function() {
return (
Input({type: "text", placeholder: "Organisation", id: "organisationInput"})
);
}
});

var CountryInput = React.createClass({displayName: 'CountryInput',
render: function() {
return (
Input({type: "text", placeholder: "Country (optional)", id: "countriesInput"})
);
}
});

var JobTitleInput = React.createClass({displayName: 'JobTitleInput',
render: function() {
return (
Input({type: "text", placeholder: "Job title (optional)", id: "jobtitleInput"})
);
}
});

var AddEmploymentForm = React.createClass({displayName: 'AddEmploymentForm',
getInitialState: function() {
return {
title: "",
response: ""
};
},

addEmployment: function() {
this.setState({
title: "Sending request",
response: "Waiting..."
});

serializedData = this.getFormData();
serializedData['user'] = this.props.user_id;

$.ajax({
type: "POST",
url: "/rest/v1/employment/?format=json",
data : JSON.stringify(serializedData),
contentType : 'application/json; charset=UTF-8',
success: function(response) {
this.setState({
title: "Request successful",
response: "Your request is now pending and will have to be approved."
});
this.handleAddEmployment(response);
}.bind(this),
error: function(response) {
if (response['status'] == 500) {
this.setState({
title: "Request failed",
response: "You're already connected to this organisation, only one link is possible."
})
} else {
this.setState({
title: "Request failed",
response: "Something went wrong..."
})
}
}.bind(this)
});
},

getFormData: function() {
var data = {
organisation: $('#organisationInput').attr('value_id'),
country: $('#countriesInput').attr('value_id'),
job_title: $('#jobtitleInput').val()
};
return data
},

handleAddEmployment: function(employment) {
this.props.addEmployment(employment);
},

render: function() {
return (
React.DOM.span(null,
React.DOM.h3(null, "Connect with an organisation"),
React.DOM.form(null,
OrganisationInput({ref: "organisationInput"}),
CountryInput({ref: "countryInput"}),
JobTitleInput({ref: "jobtitleInput"}),
ModalTrigger({modal: ResponseModal({title: this.state.title, response: this.state.response})},
Button({onClick: this.addEmployment, bsStyle: "success"}, "Request to join")
)
)
)
);
}
});

var EmploymentApp = React.createClass({displayName: 'EmploymentApp',
getInitialState: function() {
return { employments: [] }
},

componentDidMount: function() {
var employments = this.props.source.user.employments;
if (this.isMounted()) {
this.setState({
employments: employments
});
}
},

addEmployment: function(employment) {
this.setState({
employments: this.state.employments.concat([employment])
})
},

render: function() {
return (
React.DOM.span(null,
React.DOM.h2(null, "My organisations"),
EmploymentList({employments: this.state.employments}),
AddEmploymentForm({user_id: this.props.source.user.id, addEmployment: this.addEmployment})
)
);
}
});

var initial_data = JSON.parse(document.getElementById("initial-data").innerHTML);

React.renderComponent(EmploymentApp({source: initial_data}), document.getElementById('organisations'));
138 changes: 138 additions & 0 deletions akvo/rsr/static/rsr/v3/js/src/react-user-management.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/** @jsx React.DOM */

var Modal = ReactBootstrap.Modal;
var ModalTrigger = ReactBootstrap.ModalTrigger;
var Button = ReactBootstrap.Button;
var Table = ReactBootstrap.Table;

var ConfirmModal = React.createClass({displayName: 'ConfirmModal',
deleteEmployment: function() {
$.ajax({
type: "DELETE",
url: "/rest/v1/employment/" + this.props.employment.id + '/?format=json',
success: function(data) {
this.handleDelete();
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},

handleDelete: function() {
this.props.onDeleteToggle();
},

render: function() {
return this.transferPropsTo(
Modal({title: "Remove link to organisation"},
React.DOM.div({className: "modal-body"},
'Are you sure you want to remove ' + this.props.employment.user_full.first_name + ' ' + this.props.employment.user_full.last_name + ' from ' + this.props.employment.organisation_full.name + '?'
),
React.DOM.div({className: "modal-footer"},
Button({onClick: this.props.onRequestHide}, "Close"),
Button({onClick: this.deleteEmployment, bsStyle: "danger"}, "Remove")
)
)
);
}
});

var TriggerConfirmModal = React.createClass({displayName: 'TriggerConfirmModal',
render: function () {
return (
ModalTrigger({modal: ConfirmModal({employment: this.props.employment, onDeleteToggle: this.props.onDeleteToggle})},
Button({bsStyle: "danger", bsSize: "xsmall"}, "X")
)
);
}
});

var Employment = React.createClass({displayName: 'Employment',
getInitialState: function() {
return {visible: true};
},

onDelete: function() {
this.setState({visible: false});
},

render: function() {
return this.state.visible
? React.DOM.li(null, this.props.employment.organisation_full.long_name, " ", TriggerConfirmModal({employment: this.props.employment, onDeleteToggle: this.onDelete}))
: React.DOM.span(null);
}
});

var EmploymentList = React.createClass({displayName: 'EmploymentList',
getInitialState: function() {
return { employments: [] };
},

componentDidMount: function() {
var employments = this.props.user.employments;
if (this.isMounted()) {
this.setState({
employments: employments
});
}
},

render: function () {
var employments = this.state.employments.map(function(employment) {
return (
Employment({employment: employment})
)
});
return (
React.DOM.ul(null, employments)
);
}
});

var UserRow = React.createClass({displayName: 'UserRow',
render: function() {
return (
React.DOM.tr(null,
React.DOM.td(null, this.props.user.email),
React.DOM.td(null, this.props.user.first_name),
React.DOM.td(null, this.props.user.last_name),
React.DOM.td(null, EmploymentList({user: this.props.user})),
React.DOM.td(null, React.DOM.i(null, "to do"))
)
);
}
});

var UserTable = React.createClass({displayName: 'UserTable',
getInitialState: function() {
return { users: [] };
},

componentDidMount: function() {
var users = this.props.source.users;
if (this.isMounted()) {
this.setState({
users: users
});
}
},

render: function() {
var users = this.state.users.map(function(user) {
return (
UserRow({user: user})
)
});
return (
Table({striped: true},
React.DOM.thead(null, React.DOM.tr(null, React.DOM.th(null, "Email"), React.DOM.th(null, "First name"), React.DOM.th(null, "Last name"), React.DOM.th(null, "Organisations"), React.DOM.th(null, "Permissions"))),
React.DOM.tbody(null, users)
)
);
}
});

var initial_data = JSON.parse(document.getElementById("initial-data").innerHTML);

React.renderComponent(UserTable({source: initial_data}), document.getElementById('user_table'));
36 changes: 36 additions & 0 deletions mysql2pgsql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# if a socket is specified we will use that
# if tcp is chosen you can use compression
mysql:
hostname: mysql-localdev.localdev.akvo.org
port: 3306
username: rsr
password: password
database: rsr
compress: false
destination:
# if file is given, output goes to file, else postgres
file:
postgres:
hostname: 192.168.50.101
port: 5432
username: rsr
password: password
database: rsr

# if tables is given, only the listed tables will be converted. leave empty to convert all tables.
#only_tables:
#- table1
#- table2
# if exclude_tables is given, exclude the listed tables from the conversion.
#exclude_tables:
#- table3
#- table4

# if supress_data is true, only the schema definition will be exported/migrated, and not the data
supress_data: false

# if supress_ddl is true, only the data will be exported/imported, and not the schema
supress_ddl: false

# if force_truncate is true, forces a table truncate before table loading
force_truncate: false
Loading

0 comments on commit 93821a3

Please sign in to comment.