Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

Commit

Permalink
Minimally write new accounts to the db
Browse files Browse the repository at this point in the history
  • Loading branch information
chadwhitacre committed Sep 17, 2015
1 parent 1c3db55 commit 52920d0
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 10 deletions.
3 changes: 2 additions & 1 deletion sql/branch.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
BEGIN;

CREATE TABLE accounts
(
( number varchar(32) unique not null
, name varchar(32) unique not null
);

END;
58 changes: 50 additions & 8 deletions www/assets/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ Dashboard.Router = Backbone.Router.extend({
// ======

Dashboard.models.Account = Backbone.Model.extend({
idAttribute: 'number',
defaults: {
number: null,
name: null,
type: null
}
});

Expand Down Expand Up @@ -73,22 +73,22 @@ Dashboard.views.GeneralLedger = Backbone.View.extend({
Dashboard.views.ChartOfAccounts = Backbone.View.extend({
el: '#chart-of-accounts',
initialize: function() {
new Dashboard.views.AccountsListing;
new Dashboard.views.AddAccountWidget;
this.collection = new Dashboard.collections.Accounts();
new Dashboard.views.AccountsListing({collection: this.collection});
new Dashboard.views.AddAccountWidget({collection: this.collection});
},
});


Dashboard.views.AccountsListing = Backbone.View.extend({
el: '#chart-of-accounts tbody',
initialize: function() {
this.data = new Dashboard.collections.Accounts();
this.listenTo(this.data, 'reset', this.render);
this.data.fetch({reset:true});
this.listenTo(this.collection, 'reset', this.render);
this.collection.fetch({reset:true});
},
render: function() {
this.$el.html('');
this.data.each(this.addOne, this);
this.collection.each(this.addOne, this);
return this;
},
addOne: function(account) {
Expand Down Expand Up @@ -136,14 +136,56 @@ Dashboard.views.AddAccountWidget = Backbone.View.extend({
this.addAccount();
},
addAccount: function() {
alert('clicked!');

var data = { number: this.$('input[name=number]').val()
, name: this.$('input[name=name]').val()
};
if (data.number && data.name)
this.collection.create(data);
}
});


// CSRF
// ====
// WET - see js/gratipay/forms.js
//
Dashboard.getCookie = function(key) {
var o = new RegExp("(?:^|; ?)" + escape(key) + "=([^;]+)").exec(document.cookie);
return o && unescape(o[1]);
}

Dashboard.initCSRF = function() {
jQuery(document).ajaxSend(function(event, xhr, settings) {
function sameOrigin(url) {
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
function safeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
// We have to avoid httponly on the csrf_token cookie because of this.
// https://github.com/gratipay/gratipay.com/issues/3030
xhr.setRequestHeader("X-CSRF-TOKEN", Dashboard.getCookie('csrf_token'));
}
});
};


// Entrypoint
// ==========

Dashboard.init = function() {
new Dashboard.views.Main();
Dashboard.initCSRF();
};
2 changes: 1 addition & 1 deletion www/dashboard/%index.spt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ if not user.ADMIN:
<link rel="stylesheet" type="text/css" href="//cloud.typography.com/6540672/615104/css/fonts.css" />
<script src="{{ website.asset('jquery.min.js') }}"></script>
<script src="{{ website.asset('underscore-min.js') }}"></script>
<script src="{{ website.asset('backbone-min.js') }}"></script>
<script src="{{ website.asset('backbone.js') }}"></script>
<script src="{{ website.asset('dashboard.js') }}"></script>
<script>
$(document).ready(Dashboard.init);
Expand Down
31 changes: 31 additions & 0 deletions www/v2/accounts/%number.spt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import re
from aspen import Response
from psycopg2 import IntegrityError

number_re = re.compile(r'^[0-9-]{1,32}$')
name_re = re.compile(r'^[A-Za-z0-9 ~-]{1,32}$')
[---]
if user.ANON: raise Response(401)
if not user.ADMIN: raise Response(403)

request.allow('GET', 'PUT')

number = request.path['number']
if not number_re.match(number):
raise Response(404)

if request.method == 'PUT':
name = request.body.get('name')
if not name_re.match(name):
raise Response(400, 'Invalid name.')
with website.db.get_cursor() as c:
try:
website.db.run("INSERT INTO accounts (number, name) VALUES (%s, %s)", (number, name))
except IntegrityError:
website.db.run("UPDATE accounts SET name=%s WHERE number=%s")

out = website.db.one("SELECT * FROM accounts WHERE number=%s", (number,))
if not out:
raise Response(404)
[---] application/json via json_dump
out

0 comments on commit 52920d0

Please sign in to comment.