Skip to content
This repository has been archived by the owner on Nov 21, 2020. It is now read-only.

Commit

Permalink
Merge pull request #156 from Kinto/do-not-give-everyone-permission-to…
Browse files Browse the repository at this point in the history
…-read-answers

Do not give everyone permission to read answers
  • Loading branch information
almet authored Oct 21, 2016
2 parents 519bb65 + cdab572 commit 3f4e4a2
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 69 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ $ npm install
$ npm run start
```

You also need to have a [Kinto](https://kinto.readthedocs.io) server running,
in order to store your data. If you don't already have one, follow [the
You also need to have a [Kinto](https://kinto.readthedocs.io) server **greater
than 4.3.1** in order to store your data. If you don't already have one, follow [the
installation instructions](http://kinto.readthedocs.io/en/stable/tutorials/install.html)!

# Configuration
Expand Down
91 changes: 39 additions & 52 deletions formbuilder/actions/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import btoa from "btoa";
import uuid from "uuid";

import {addNotification} from "./notifications";
import {getUserToken} from "../utils";
import {getFormID} from "../utils";
import config from "../config";


Expand Down Expand Up @@ -84,56 +84,43 @@ export function publishForm(callback) {

dispatch({type: FORM_PUBLICATION_PENDING});
const adminToken = uuid.v4().replace(/-/g, "");
const userToken = getUserToken(adminToken);
const formID = getFormID(adminToken);

const userClient = new KintoClient(
// Create a client authenticated as the admin.
const bucket = new KintoClient(
config.server.remote,
{headers: getAuthenticationHeaders(userToken)}
);
userClient.fetchServerInfo().then((serverInfo) => {
return serverInfo.user.id;
})
.catch(() => {
connectivityIssues(dispatch, "We are unable to connect to the server.");
dispatch({type: FORM_PUBLICATION_FAILED});
{headers: getAuthenticationHeaders(adminToken)}
).bucket(config.server.bucket);

// The name of the collection is the user token so the user deals with
// less different concepts.
bucket.createCollection(formID, {
data: {schema, uiSchema},
permissions: {
"record:create": ["system.Authenticated"]
}
})
.then((userId) => {
// Create a new client, authenticated as the admin.
const bucket = new KintoClient(
config.server.remote,
{headers: getAuthenticationHeaders(adminToken)}
).bucket(config.server.bucket);
// The name of the collection is the user token so the user deals with
// less different concepts.
bucket.createCollection(userToken, {
data: {schema, uiSchema},
permissions: {
"record:create": ["system.Authenticated"],
"read": [userId]
}
})
.then(({data}) => {
dispatch({
type: FORM_PUBLICATION_DONE,
.then(({data}) => {
dispatch({
type: FORM_PUBLICATION_DONE,
collection: data.id,
});
if (callback) {
callback({
collection: data.id,
adminToken,
});
if (callback) {
callback({
collection: data.id,
adminToken,
});
}
})
.catch((error) => {
// If the bucket doesn't exist, try to create it.
if (error.response.status === 403 && retry === true) {
return initializeBucket().then(() => {
thunk(dispatch, getState, false);
});
}
connectivityIssues(dispatch, "We were unable to publish your form.");
dispatch({type: FORM_PUBLICATION_FAILED});
});
}
})
.catch((error) => {
// If the bucket doesn't exist, try to create it.
if (error.response.status === 403 && retry === true) {
return initializeBucket().then(() => {
thunk(dispatch, getState, false);
});
}
connectivityIssues(dispatch, "We were unable to publish your form.");
dispatch({type: FORM_PUBLICATION_FAILED});
});
};
return thunk;
Expand Down Expand Up @@ -167,14 +154,14 @@ export function submitRecord(record, collection, callback) {
};
}

export function loadSchema(collection, callback) {
export function loadSchema(formID, callback) {
return (dispatch, getState) => {
dispatch({type: SCHEMA_RETRIEVAL_PENDING});
new KintoClient(config.server.remote, {
headers: getAuthenticationHeaders(collection)
headers: getAuthenticationHeaders("EVERYONE")
})
.bucket(config.server.bucket)
.collection(collection)
.collection(formID)
.getData().then((data) => {
dispatch({
type: SCHEMA_RETRIEVAL_DONE,
Expand All @@ -193,17 +180,17 @@ export function loadSchema(collection, callback) {
/**
* Retrieve all the answers to a specific form.
*
* The userToken is derived from the the adminToken.
* The formID is derived from the the adminToken.
**/
export function getRecords(adminToken, callback) {
return (dispatch, getState) => {
const collection = getUserToken(adminToken);
const formID = getFormID(adminToken);
dispatch({type: RECORDS_RETRIEVAL_PENDING});
new KintoClient(config.server.remote, {
headers: getAuthenticationHeaders(adminToken)
})
.bucket(config.server.bucket)
.collection(collection)
.collection(formID)
.listRecords().then(({data}) => {
dispatch({
type: RECORDS_RETRIEVAL_DONE,
Expand Down
8 changes: 4 additions & 4 deletions formbuilder/components/AdminView.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import React, { Component } from "react";
import CSVDownloader from "./CSVDownloader";
import URLDisplay from "./URLDisplay";
import {getUserToken, getUserURL} from "../utils";
import {getFormID, getFormURL} from "../utils";

export default class AdminView extends Component {
componentDidMount() {
const adminToken = this.props.params.adminToken;
this.userToken = getUserToken(adminToken);
this.formID = getFormID(adminToken);
this.props.getRecords(adminToken);
this.props.loadSchema(this.userToken);
this.props.loadSchema(this.formID);
}
render() {
const properties = this.props.schema.properties;
const title = this.props.schema.title;
const ready = Object.keys(properties).length !== 0;
const schemaFields = this.props.uiSchema["ui:order"];
const formUrl = getUserURL(this.userToken);
const formUrl = getFormURL(this.formID);

let content = "loading";
if (ready) {
Expand Down
6 changes: 3 additions & 3 deletions formbuilder/components/FormCreated.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from "react";
import {getUserToken, getUserURL, getAdminURL} from "../utils";
import {getFormID, getFormURL, getAdminURL} from "../utils";
import URLDisplay from "./URLDisplay";

export default function FormCreated(props) {
const adminToken = props.params.adminToken;
const userToken = getUserToken(adminToken);
const formID = getFormID(adminToken);

const userformURL = getUserURL(userToken);
const userformURL = getFormURL(formID);
const adminURL = getAdminURL(adminToken);

return (
Expand Down
16 changes: 8 additions & 8 deletions formbuilder/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@ import config from "./config";


/**
* Returns the user token from the administration token.
* Returns the form unique identifier from the administration token.
*
* The user token is also used as the name of the collection where the records
* are stored. This is useful to always have one id to pass to the clients,
* and they can figure out what the user token and collection name is.
* The form ID is used as the name of the collection where the records
* are stored. This is useful to always have one ID to pass to the clients,
* and they can figure out what the collection name is.
**/
export function getUserToken(adminToken) {
export function getFormID(adminToken) {
return adminToken.slice(0, adminToken.length / 2);
}

/**
* Returns the user URL from the user token.
* Returns the form URL from the form identifier.
*
* This function relies on the globally available "window" object, which might
* be something we want to pass rather than relying on it being globally
* available.
**/
export function getUserURL(userToken) {
return `${config.appURL}#/form/${userToken}`;
export function getFormURL(formID) {
return `${config.appURL}#/form/${formID}`;
}

/**
Expand Down

0 comments on commit 3f4e4a2

Please sign in to comment.