...
 
Commits (4)
export const REQUEST_AMENDMENTS = 'REQUEST_AMENDMENTS';
export const RECEIVE_AMENDMENTS = 'RECEIVE_AMENDMENTS';
function requestAmendments(project) {
return {
type: REQUEST_AMENDMENTS,
project,
};
}
function receiveAmendments(project, amendments) {
return {
type: RECEIVE_AMENDMENTS,
project,
amendments,
receivedAt: Date.now()
};
}
function fetchAmendments(project) {
return dispatch => {
dispatch(requestAmendments(project));
return fetch(`/api/v1/project/${project}/amendment`, {credentials: 'same-origin'})
.then(response => response.json())
.then(json => dispatch(receiveAmendments(project, json)));
}
}
function shouldFetchAmendments(state, projectId) {
return !state.amendmentsByProject[projectId].items
&& !state.amendmentsByProject[projectId].isFetching;
}
export function fetchAmendmentsIfNeeded(project) {
return (dispatch, getState) => {
if (shouldFetchAmendments(getState(), project)) {
return dispatch(fetchAmendments(project));
}
}
}
import React, { Component } from 'react';
import { List, ListItem } from 'react-toolbox/lib/list';
import {
fetchAmendmentsIfNeeded,
} from '../action/amendment';
export default class AmendmentList extends Component {
// FIXME: should come from the API via redux
amendements = [
{
id: 0,
title: "Dr. Manhattan",
description: "Exemple d'amendement soumis",
status: "done",
},
{
id: 1,
title: "Ozymandias",
description: "Exemple d'amendement accepté",
status: "done_all",
},
{
id: 2,
title: "Rorschach",
description: "Exemple d'amendement en cours de rédaction",
status: "mode_edit",
},
{
id: 3,
title: "The Comedian",
description: "Exemple d'amendement rejeté",
status: "not_interested",
componentDidMount() {
const { dispatch, project } = this.props;
if (!project) {
return ;
}
];
dispatch(fetchAmendmentsIfNeeded(project));
}
componentDidUpdate() {
const { dispatch, project } = this.props;
if (!project) {
return ;
}
dispatch(fetchAmendmentsIfNeeded(project));
}
render() {
if (!this.props.amendments || !this.props.amendments.items) {
return null;
}
return (
<List selectable ripple>
{
this.amendements.map((amendement) =>
this.props.amendments.items.map((amendement) =>
<ListItem
key={amendement.id}
caption={amendement.title}
legend={amendement.description}
leftIcon={amendement.status}
// leftIcon={amendement.status}
onClick={() => this.props.onAmendmentClick(amendement.id)}
/>
)
......
......@@ -16,7 +16,7 @@ import './App.css';
import theme from '../asset/react-toolbox/theme';
import ArticleListContainer from '../container/ArticleListContainer';
import HeaderContainer from '../container/HeaderContainer';
import AmendmentList from './AmendmentList';
import AmendmentListContainer from '../container/AmendmentListContainer';
import {
selectProject,
......@@ -25,7 +25,6 @@ import {
class App extends Component {
state = {
index: 0,
selectedAmendment: false,
user: null,
};
......@@ -39,13 +38,6 @@ class App extends Component {
handleTabChange = (index) => {
this.setState({
index,
selectedAmendment: false,
});
};
handleAmendmentClick = (amendmentId) => {
this.setState({
selectedAmendment: this.amendements.filter((a) => a.id === amendmentId)[0]
});
};
......@@ -62,23 +54,8 @@ class App extends Component {
<Tab label='Projet de loi'>
<ArticleListContainer project={this.props.selectedProject}/>
</Tab>
<Tab
label='Amendements (4)'
onActive={this.handleActive}>
{
this.state.selectedAmendment === false
?
<AmendmentList onAmendmentClick={(id) => this.handleAmendmentClick(id)}/>
:
<section>
<h1>
{this.state.selectedAmendment.title}
</h1>
<p>
{this.state.selectedAmendment.description}
</p>
</section>
}
<Tab label='Amendements' onActive={this.handleActive}>
<AmendmentListContainer project={this.props.selectedProject}/>
</Tab>
</Tabs>
</div>
......
import { connect } from 'react-redux';
import AmendmentList from '../component/AmendmentList';
const mapStateToProps = state => {
return {
amendments: state.amendmentsByProject[state.selectedProject],
}
};
export default connect(mapStateToProps)(AmendmentList);
import {
INVALIDATE_PROJECT,
SELECT_PROJECT,
} from '../action/project';
import {
REQUEST_AMENDMENTS,
RECEIVE_AMENDMENTS,
} from '../action/amendment';
function amendments(
state = {
isFetching: false,
didInvalidate: false,
items: [],
},
action
) {
switch (action.type) {
case INVALIDATE_PROJECT:
return {
...state,
didInvalidate: true,
}
case REQUEST_AMENDMENTS:
return {
...state,
isFetching: true,
didInvalidate: false,
};
case RECEIVE_AMENDMENTS:
return {
...state,
isFetching: false,
didInvalidate: false,
items: action.amendments,
lastUpdated: action.receivedAt,
};
default:
return state;
}
}
export default function amendmentsByProject(state = {}, action) {
switch (action.type) {
case SELECT_PROJECT:
return {...state, [action.project]: {}};
case INVALIDATE_PROJECT:
case RECEIVE_AMENDMENTS:
case REQUEST_AMENDMENTS:
return {
...state,
[action.project]: amendments(state[action.project], action),
};
default:
return state;
}
}
......@@ -2,11 +2,13 @@ import { combineReducers } from 'redux';
import selectedProject from './selectedProject';
import articlesByProject from './articlesByProject';
import articleContentById from './articleContentById';
import amendmentsByProject from './amendmentsByProject';
import user from './user';
export default combineReducers({
selectedProject,
articlesByProject,
articleContentById,
amendmentsByProject,
user,
});
......@@ -3,8 +3,7 @@
"version": "1.0.0",
"scripts": {
"start": "nodemon -L src/index.js",
"test": "echo \"Error: no test specified\" && exit 1",
"create-oauth-application": "babel script/create-oauth-application.js | nodejs - --"
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "AGPL-3.0",
"dependencies": {
......
#!/usr/bin/env node
const puppeteer = require('puppeteer');
const argv = require('yargs-parser')(process.argv.slice(3));
const argv = require('yargs-parser')(process.argv.slice(2));
(async () => {
const browser = await puppeteer.launch({
ignoreHTTPSErrors: true,
// This script is running as root during Ansible provisioning because
// it's stdout is redirected to /etc/amenda/oauth.json, so Chrome
// must run without the sandbox.
// https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#chrome-headless-fails-due-to-sandbox-issues
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
await page.goto('https://127.0.0.1/admin');
const user_login = await page.$('#user_login');
const user_password = await page.$('#user_password');
const login_submit_btn = await page.$('.login-body .btn-save');
await user_login.type('root');
await user_password.type('adminadmin');
await login_submit_btn.click();
await page.waitForNavigation();
await page.goto('https://127.0.0.1/admin/admin/applications/new');
const application_name = await page.$('#doorkeeper_application_name');
const application_redirect_uri = await page.$('#doorkeeper_application_redirect_uri');
const application_trusted = await page.$('#doorkeeper_application_trusted');
const application_scopes_api = await page.$('#doorkeeper_application_scopes_api');
const application_scopes_read_user = await page.$('#doorkeeper_application_scopes_read_user');
const application_scopes_read_registry = await page.$('#doorkeeper_application_scopes_read_registry');
const application_scopes_openid = await page.$('#doorkeeper_application_scopes_openid');
const application_submit_btn = await page.$('#new_doorkeeper_application .btn-save');
await application_name.type(argv['name']);
await application_redirect_uri.type(argv['redirect-urls'].split(',').join('\n'));
await application_trusted.click();
await application_scopes_api.click();
await application_scopes_read_user.click();
await application_scopes_read_registry.click();
await application_scopes_openid.click();
await application_submit_btn.click();
await page.waitForNavigation();
const application = await page.evaluate(() => {
var application_id = document.getElementById('application_id');
var application_secret = document.getElementById('secret');
return {
app_id: application_id.innerHTML,
app_secret: application_secret.innerHTML,
}
});
console.log(JSON.stringify(application, null, 2));
await browser.close();
try {
const browser = await puppeteer.launch({
ignoreHTTPSErrors: true,
// This script is running as root during Ansible provisioning because
// its stdout is redirected to /etc/amenda/oauth.json, so Chrome
// must run without the sandbox.
// https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#chrome-headless-fails-due-to-sandbox-issues
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
await page.goto('https://127.0.0.1/admin');
const user_login = await page.$('#user_login');
const user_password = await page.$('#user_password');
const login_submit_btn = await page.$('.login-body .btn-save');
await user_login.type('root');
await user_password.type('adminadmin');
await login_submit_btn.click();
await page.waitForNavigation();
await page.goto('https://127.0.0.1/admin/admin/applications/new');
const application_name = await page.$('#doorkeeper_application_name');
const application_redirect_uri = await page.$('#doorkeeper_application_redirect_uri');
const application_trusted = await page.$('#doorkeeper_application_trusted');
const application_scopes_api = await page.$('#doorkeeper_application_scopes_api');
const application_scopes_read_user = await page.$('#doorkeeper_application_scopes_read_user');
const application_scopes_sudo = await page.$('#doorkeeper_application_scopes_sudo');
const application_scopes_openid = await page.$('#doorkeeper_application_scopes_openid');
const application_submit_btn = await page.$('#new_doorkeeper_application .btn-save');
await application_name.type(argv['name']);
await application_redirect_uri.type(argv['redirect-urls'].split(',').join('\n'));
await application_trusted.click();
await application_scopes_api.click();
await application_scopes_read_user.click();
await application_scopes_sudo.click();
await application_scopes_openid.click();
await application_submit_btn.click();
await page.waitForNavigation();
const application = await page.evaluate(() => {
var application_id = document.getElementById('application_id');
var application_secret = document.getElementById('secret');
return {
app_id: application_id.innerHTML,
app_secret: application_secret.innerHTML,
}
});
console.log(JSON.stringify(application, null, 2));
await browser.close();
} catch (e) {
console.error(e);
process.exit(1);
}
})();
......@@ -8,6 +8,7 @@ docker_group_members:
nodejs_version: "8.x"
gitlab_version: 10.2.8-ce.0
gitlab_admin_email: "admin@{{ hostname }}"
gitlab_admin_password: "adminadmin"
......
......@@ -3,7 +3,7 @@
- name: Install Gitlab (via Docker)
docker_container:
name: gitlab
image: gitlab/gitlab-ce:10.0.1-ce.0
image: "gitlab/gitlab-ce:{{ gitlab_version }}"
state: started
restart_policy: always
hostname: "{{ hostname }}"
......
---
- meta: flush_handlers
- name: Install dependencies
npm:
path: /vagrant/oauth
......@@ -48,8 +50,13 @@
- xdg-utils
- wget
- name: Create /etc/amenda
file:
path: /etc/amenda
state: directory
- name: Register the OAuth client application on GitLab
shell: "npm run -s create-oauth-application -- --name '{{ oauth_app_name }}' --redirect-urls '{{ oauth_app_redirect_urls | join(',') }}' --username '{{ gitlab_admin_email }}' --password '{{ gitlab_admin_password }}' > /etc/amenda/oauth.json"
shell: "./script/create-oauth-application.js --name '{{ oauth_app_name }}' --redirect-urls '{{ oauth_app_redirect_urls | join(',') }}' --username '{{ gitlab_admin_email }}' --password '{{ gitlab_admin_password }}' > /etc/amenda/oauth.json"
args:
chdir: /vagrant/oauth/
creates: /etc/amenda/oauth.json
......