[guadec-web-regcfp/develop] Add registration system
- From: Patrick Uiterwijk <puiterwijk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [guadec-web-regcfp/develop] Add registration system
- Date: Tue, 2 Jun 2015 11:23:47 +0000 (UTC)
commit 65fabb80891a22be277470e5d75eec4c207f3fe8
Author: Patrick Uiterwijk <puiterwijk redhat com>
Date: Tue Jun 2 13:23:13 2015 +0200
Add registration system
app.js | 10 ++
models/registration.js | 46 +++++++
models/registrationpayment.js | 18 +++
models/user.js | 1 +
routes/index.js | 21 ++--
routes/papers.js | 2 +
routes/registration.js | 157 ++++++++++++++++++++++
utils.js | 38 +++++-
views/index/index.hbs | 26 ++++-
views/partials/registration/payment.hbs | 10 ++
views/registration/list.hbs | 6 +
views/registration/pay.hbs | 20 +++
views/registration/pay_do.hbs | 1 +
views/registration/payment_onsite_registered.hbs | 2 +
views/registration/register.hbs | 53 ++++++++
views/registration/registration_success.hbs | 3 +
views/registration/update_success.hbs | 2 +
17 files changed, 395 insertions(+), 21 deletions(-)
---
diff --git a/app.js b/app.js
index 7145bb6..5a0bc7e 100644
--- a/app.js
+++ b/app.js
@@ -39,6 +39,13 @@ var hbs = handlebars.create({
} else {
return options.inverse(this);
}
+ },
+ ifGTE: function(v1, v2, options) {
+ if(v1 >= v2) {
+ return options.fn(this);
+ } else {
+ return options.inverse(this);
+ }
}
}
});
@@ -75,6 +82,9 @@ app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
+// Get user if we have any
+app.use(utils.get_user);
+
// Routing
app.use('/', routes_index);
app.use('/auth', routes_auth);
diff --git a/models/registration.js b/models/registration.js
new file mode 100644
index 0000000..d9c1581
--- /dev/null
+++ b/models/registration.js
@@ -0,0 +1,46 @@
+"use strict";
+
+module.exports = function(sequelize, DataTypes) {
+ var Registration = sequelize.define("Registration", {
+ irc: DataTypes.STRING,
+ is_public: DataTypes.BOOLEAN,
+ badge_printed: DataTypes.BOOLEAN,
+ receipt_sent: DataTypes.BOOLEAN,
+ gender: DataTypes.ENUM('male', 'female', 'other'),
+ country: DataTypes.STRING,
+ }, {
+ classMethods: {
+ associate: function(models) {
+ Registration.belongsTo(models.User);
+ Registration.hasMany(models.RegistrationPayment);
+ }
+ },
+ getterMethods: {
+ display_id: function() {
+ return this.id;
+ },
+ paid: function() {
+ var amount = 0;
+ for(var payment in this.RegistrationPayments) {
+ payment = this.RegistrationPayments[payment];
+ if(payment.paid) {
+ amount += payment.amount;
+ }
+ }
+ return amount;
+ },
+ outstanding: function() {
+ var amount = 0;
+ for(var payment in this.RegistrationPayments) {
+ payment = this.RegistrationPayments[payment];
+ if(!payment.paid) {
+ amount += payment.amount;
+ }
+ }
+ return amount;
+ }
+ }
+ });
+
+ return Registration;
+};
diff --git a/models/registrationpayment.js b/models/registrationpayment.js
new file mode 100644
index 0000000..ce2e9a2
--- /dev/null
+++ b/models/registrationpayment.js
@@ -0,0 +1,18 @@
+"use strict";
+
+module.exports = function(sequelize, DataTypes) {
+ var RegistrationPayment = sequelize.define("RegistrationPayment", {
+ amount: DataTypes.FLOAT,
+ paid: DataTypes.BOOLEAN,
+ type: DataTypes.ENUM('paypal', 'onsite'),
+ details: DataTypes.STRING,
+ }, {
+ classMethods: {
+ associate: function(models) {
+ RegistrationPayment.belongsTo(models.Registration);
+ }
+ }
+ });
+
+ return RegistrationPayment;
+};
diff --git a/models/user.js b/models/user.js
index d107e4c..5434fac 100644
--- a/models/user.js
+++ b/models/user.js
@@ -9,6 +9,7 @@ module.exports = function(sequelize, DataTypes) {
associate: function(models) {
User.hasMany(models.Paper);
User.hasMany(models.PaperVote);
+ User.hasOne(models.Registration);
}
}
});
diff --git a/routes/index.js b/routes/index.js
index 7fb3897..90fa2b7 100644
--- a/routes/index.js
+++ b/routes/index.js
@@ -3,6 +3,8 @@ var router = express.Router();
var models = require('../models');
var User = models.User;
+var Registration = models.Registration;
+var RegistrationPayment = models.RegistrationPayment;
var env = process.env.NODE_ENV || "development";
var config = require(__dirname + '/../config/config.json')[env];
@@ -12,19 +14,14 @@ var config = require(__dirname + '/../config/config.json')[env];
router.get('/', function(req, res, next) {
if(req.session.currentUser)
{
- User
- .find({
- where: {
- email: req.session.currentUser
- }
- })
- .complete(function(err, user) {
- if(user) {
- res.render('index/index', { 'name': user.name });
- } else {
- res.render('index/index', { 'name': req.session.currentUser });
- }
+ if(req.user) {
+ req.user.getRegistration({include: [RegistrationPayment]})
+ .complete(function(err, reg) {
+ res.render('index/index', { name: req.user.name, registration: reg });
});
+ } else {
+ res.render('index/index', { name: req.session.currentUser });
+ }
} else {
res.render('index/index', { });
}
diff --git a/routes/papers.js b/routes/papers.js
index d2027be..9ca8195 100644
--- a/routes/papers.js
+++ b/routes/papers.js
@@ -8,6 +8,8 @@ var User = models.User;
var Paper = models.Paper;
var PaperVote = models.PaperVote;
+router.all('/', utils.require_feature('papers'));
+
router.all('/submit', utils.require_user);
router.all('/submit', utils.require_permission('papers/submit'));
router.get('/submit', function(req, res, next) {
diff --git a/routes/registration.js b/routes/registration.js
index 6309524..d637a97 100644
--- a/routes/registration.js
+++ b/routes/registration.js
@@ -5,7 +5,164 @@ var utils = require('../utils');
var models = require('../models');
var User = models.User;
+var Registration = models.Registration;
+var RegistrationPayment = models.RegistrationPayment;
+var all_genders = ['male', 'female', 'other'];
+router.all('/', utils.require_feature("registration"));
+
+router.all('/list', utils.require_permission('registration/view_public'));
+router.get('/list', function(req, res, next) {
+ Registration
+ .findAll({
+ where: {
+ is_public: true
+ }
+ })
+ .complete(function(err, registrations) {
+ res.render('registration/list', { registrations: registrations });
+ });
+});
+
+router.all('/pay', utils.require_user);
+router.all('/pay', utils.require_permission('registration/pay_extra'));
+router.get('/pay', function(req, res, next) {
+ res.render('registration/pay');
+});
+
+router.post('/pay', function(req, res, next) {
+ var regfee = req.body.regfee;
+ if(regfee == 'custom')
+ {
+ regfee = req.body.regfee_custom.trim();
+ }
+
+ if(regfee == null) {
+ res.render('registration/pay');
+ } else {
+ res.render('registration/pay_do', {regfee: regfee});
+ }
+});
+
+router.all('/pay/do', utils.require_user);
+router.all('/pay/do', utils.require_permission('registration/pay_extra'));
+router.post('/pay/do', function(req, res, next) {
+ var method = req.body.method;
+ if(method == 'onsite') {
+ var info = {
+ amount: req.body.regfee,
+ paid: false,
+ type: 'onsite',
+ };
+ RegistrationPayment
+ .create(info)
+ .complete(function(err, payment) {
+ if(!!err) {
+ console.log('Error saving payment: ' + err);
+ res.status(500).send('ERROR saving payment');
+ } else {
+ req.user.getRegistration()
+ .complete(function(err, reg) {
+ reg.addRegistrationPayment(payment)
+ .complete(function(err) {
+ if(!!err) {
+ console.log('Error attaching payment to reg: ' + err);
+ res.status(500).send('Error attaching payment');
+ } else {
+ res.render('registration/payment_onsite_registered', {amount: info.amount});
+ }
+ });
+ });
+ }
+ });
+ } else {
+ res.status(402).send('Invalid payment method selected');
+ }
+});
+
+router.all('/register', utils.require_user);
+router.all('/register', utils.require_permission('registration/register'));
+router.get('/register', function(req, res, next) {
+ req.user.getRegistration()
+ .complete(function(err, reg) {
+ res.render('registration/register', { registration: reg, genders: all_genders });
+ });
+});
+
+router.post('/register', function(req, res, next) {
+ req.user.getRegistration({include: [RegistrationPayment]})
+ .complete(function(err, reg) {
+ console.log('Body: ' + JSON.stringify(req.body));
+ var reg_info = {
+ irc: req.body.irc.trim(),
+ is_public: req.body.is_public.indexOf('true') != -1,
+ gender: req.body.gender,
+ country: req.body.country.trim(),
+ badge_printed: false,
+ receipt_sent: false,
+ UserId: req.user.Id,
+ is_not_saved: true
+ };
+
+ console.log("Reg info: " + JSON.stringify(reg_info));
+
+ var regfee = req.body.regfee;
+ if(regfee == 'custom')
+ {
+ regfee = req.body.regfee_custom.trim();
+ }
+
+ if((all_genders.indexOf(reg_info.gender) == -1) || (reg == null && regfee == null)) {
+ res.render('registration/register', { registration: reg_info, genders: all_genders,
+ submission_error: true});
+ } else {
+ // Form OK
+ if(reg == null) {
+ console.log("CREATING");
+ // Create new registration
+ Registration.create(reg_info)
+ .complete(function(err, reg) {
+ if(!!err) {
+ console.log('Error saving reg: ' + err);
+ res.status(500).send('Error saving registration');
+ } else {
+ req.user.setRegistration(reg)
+ .complete(function(err) {
+ if(!!err) {
+ console.log('Error adding reg to user: ' + err);
+ res.status(500).send('Error attaching registration to your user');
+ } else {
+ res.render('registration/registration_success', {regfee: regfee});
+ }
+ });
+ }
+ });
+ } else {
+ // Update
+ console.log("UPDATING");
+ reg.irc = reg_info.irc;
+ reg.is_public = reg_info.is_public;
+ reg.gender = reg_info.gender;
+ reg.country = reg_info.country;
+ reg.save().complete(function (err, reg){
+ if(!!err) {
+ res.render('registration/register', { registration: reg_info, genders: all_genders,
+ save_error: true });
+ } else {
+ res.render('registration/update_success');
+ }
+ });
+ }
+ }
+ });
+});
+
+
+router.all('/admin/list', utils.require_user);
+router.all('/admin/list', utils.require_permission('registration/view_all'));
+router.get('/admin/list', function(req, res, next) {
+ next();
+});
module.exports = router;
diff --git a/utils.js b/utils.js
index 977da57..466206e 100644
--- a/utils.js
+++ b/utils.js
@@ -69,12 +69,23 @@ utils.require_login = function(req, res, next) {
}
};
-utils.require_user = function(req, res, next) {
+utils.require_feature = function(feature) {
+ if(config[feature]['enabled']) {
+ return function(req, res, next) {
+ next();
+ }
+ } else {
+ return function(req, res, next) {
+ res.render('auth/no_permission', { required_permission: 'Feature disabled' });
+ }
+ }
+};
+
+utils.get_user = function(req, res, next) {
if(!req.session.currentUser) {
- res.render('auth/no_permission', { required_permission: 'Login' });
+ next();
return;
}
-
User.find({
where: {
email: req.session.currentUser
@@ -83,15 +94,28 @@ utils.require_user = function(req, res, next) {
.complete(function(err, user) {
if(!!err) {
res.status(500).send('Error retrieving user object');
- } else if(!user) {
- // Redirect to register
- res.redirect(302, '/auth/register?origin=' + req.originalUrl);
- } else {
+ } else if(user) {
req.user = user;
res.locals.user = user;
next();
+ } else {
+ next();
}
});
+}
+
+utils.require_user = function(req, res, next) {
+ if(!req.session.currentUser) {
+ res.render('auth/no_permission', { required_permission: 'Login' });
+ return;
+ }
+
+ if(!req.user) {
+ // Redirect to register
+ res.redirect(302, '/auth/register?origin=' + req.originalUrl);
+ } else {
+ next();
+ }
};
module.exports = utils;
diff --git a/views/index/index.hbs b/views/index/index.hbs
index e29a222..c0a1a1e 100644
--- a/views/index/index.hbs
+++ b/views/index/index.hbs
@@ -28,8 +28,27 @@ Hello, please login, or choose an option below.
{{#if config.registration.enabled}}
<h2>Registration</h2>
-.....
-
+{{#has_permission "registration/view_public"}}
+<div class="button"><a href="/registration/list">Current registrations</a></div>
+{{/has_permission}}
+<div class="buttons">
+{{#has_permission "registration/register" }}
+{{#if registration}}
+<h3>Registration ID: {{registration.display_id}}</h3>
+<div class="button"><a href="/registration/register">Update registration</a></div>
+{{#ifGTE registration.paid config.registration.min_amount_for_receipt}}
+<div class="button"><a href="/registration/receipt">Get receipt</a></div>
+{{else}}
+Not enough paid for receipt (Paid {{config.registration.currency_symbol}}{{registration.paid}}, outstanding
for onsite payment: {{config.registration.currency_symbol}}{{registration.outstanding}})
+{{/ifGTE}}
+{{#has_permission "registration/pay_extra"}}
+<div class="button"><a href="/registration/pay">Pay more</a></div>
+{{/has_permission}}
+{{else}}
+<div class="button"><a href="/registration/register">Register</a></div>
+{{/if}}
+{{/has_permission}}
+</div>
{{/if}}
@@ -51,6 +70,9 @@ Hello, please login, or choose an option below.
<h3>Registration</h3>
<div class="buttons">
+{{#has_permission "registration/view_all" }}
+<div class="button"><a href="/registration/admin/list">List all registrations</a></div>
+{{/has_permission}}
</div>
{{/has_permission}}
diff --git a/views/partials/registration/payment.hbs b/views/partials/registration/payment.hbs
new file mode 100644
index 0000000..2b6c9c1
--- /dev/null
+++ b/views/partials/registration/payment.hbs
@@ -0,0 +1,10 @@
+Your selected registration fee: {{config.registration.currency_symbol}}{{regfee}}.
+<br />
+Please select how you wish to pay:<br />
+Paypal: $INSERT_PAYPAL_BUTTON_HERE<br />
+On-site:
+<form action="/registration/pay/do" method="POST">
+<input type="hidden" name="method" value="onsite">
+<input type="hidden" name="regfee" value="{{regfee}}">
+<input type="submit" value="Pay on-site">
+</form><br />
diff --git a/views/registration/list.hbs b/views/registration/list.hbs
new file mode 100644
index 0000000..31ceb33
--- /dev/null
+++ b/views/registration/list.hbs
@@ -0,0 +1,6 @@
+<table>
+<tr><th>IRC Nick</th></tr>
+{{#each registrations}}
+<tr><td>{{this.irc}}</td></tr>
+{{/each}}
+</table>
diff --git a/views/registration/pay.hbs b/views/registration/pay.hbs
new file mode 100644
index 0000000..8105a2a
--- /dev/null
+++ b/views/registration/pay.hbs
@@ -0,0 +1,20 @@
+<form action="/registration/pay" method="post">
+<table class="submission-form">
+<tr><td>Your name:</td><td><input type="text" name="submitter_name" value="{{user.name}}" disabled
/></td></tr>
+<tr><td>Amount:</td><td>
+{{#each config.registration.fee_options}}
+<input type="radio" name="regfee" value="{{this}}" id="regfee_{{this}}">
+<label for="regfee_{{this}}">{{../config.registration.currency_symbol}}{{this}}</label>
+<br />
+{{/each}}
+<input type="radio" name="regfee" value="custom">
+<input type="text" name="regfee_custom">
+</td>
+<td>NOTE: Only registrations with a fee of at least
{{config.registration.currency_symbol}}{{config.registration.min_amount_for_receipt}} can get a receipt! (you
can always pay more)
+</td></tr>
+
+<tr><td> </td>
+<td><input class="submit-talk" type="submit" value="Submit" /></td>
+</tr>
+</table>
+</form>
diff --git a/views/registration/pay_do.hbs b/views/registration/pay_do.hbs
new file mode 100644
index 0000000..f506fa1
--- /dev/null
+++ b/views/registration/pay_do.hbs
@@ -0,0 +1 @@
+{{>registration/payment}}
diff --git a/views/registration/payment_onsite_registered.hbs
b/views/registration/payment_onsite_registered.hbs
new file mode 100644
index 0000000..1c7bebb
--- /dev/null
+++ b/views/registration/payment_onsite_registered.hbs
@@ -0,0 +1,2 @@
+Your payment has been marked as to be completed onsite, thank you!<br />
+<a href="/">Return</a>
diff --git a/views/registration/register.hbs b/views/registration/register.hbs
new file mode 100644
index 0000000..c5cb5e9
--- /dev/null
+++ b/views/registration/register.hbs
@@ -0,0 +1,53 @@
+{{#if submission_error}}
+<font color="red"><b>Something went wrong submitting. Please check you filled in all fields!</b></font>
+{{/if}}
+
+<form action="/registration/register" method="post">
+<table class="submission-form">
+<tr><td>Your name:</td><td><input type="text" name="submitter_name" value="{{user.name}}" disabled
/></td></tr>
+<tr><td>IRC nickname:</td><td><input type="text" name="irc" value="{{registration.irc}}"></td></tr>
+<input type="hidden" name="is_public" value="false">
+<tr><td>Registration public:</td><td><input type="checkbox" value="true" name="is_public"
+{{#if registration.is_public}}
+checked
+{{/if}}
+></td></tr>
+
+<tr><td>Registration fee:</td><td>
+{{#unless registration.is_not_saved}}
+Registered
+{{else}}
+{{#each config.registration.fee_options}}
+<input type="radio" name="regfee" value="{{this}}" id="regfee_{{this}}">
+<label for="regfee_{{this}}">{{../config.registration.currency_symbol}}{{this}}</label>
+<br />
+{{/each}}
+<input type="radio" name="regfee" value="custom">
+<input type="text" name="regfee_custom">
+</td>
+<td>NOTE: Only registrations with a fee of at least
{{config.registration.currency_symbol}}{{config.registration.min_amount_for_receipt}} can get a receipt! (you
can always pay more)
+{{/unless}}
+</td></tr>
+
+<tr><td colspan="2">Always private info for stats:</td></tr>
+<tr><td>Gender:</td><td>
+{{#each genders}}
+<input type="radio" name="gender" value="{{this}}" id="gender_{{this}}"
+{{#ifEqual ../registration/gender this}}
+checked
+{{/ifEqual}}
+>
+<label for="gender_{{this}}">{{this}}</label>
+{{/each}}
+</td></tr>
+
+<tr><td>Country:</td><td><input type="text" name="country" value="{{registration.country}}"></td></tr>
+
+
+
+<tr><td> </td>
+<td><input class="submit-talk" type="submit" value="Submit" /></td>
+</tr>
+
+</table>
+</form>
diff --git a/views/registration/registration_success.hbs b/views/registration/registration_success.hbs
new file mode 100644
index 0000000..6ea630b
--- /dev/null
+++ b/views/registration/registration_success.hbs
@@ -0,0 +1,3 @@
+Your registration was recorded, thank you!<br />
+
+{{>registration/payment}}
diff --git a/views/registration/update_success.hbs b/views/registration/update_success.hbs
new file mode 100644
index 0000000..513cdfa
--- /dev/null
+++ b/views/registration/update_success.hbs
@@ -0,0 +1,2 @@
+Your registration was updated, thank you!<br />
+<a href="/">Return</a>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]