Skip to content

Commit 9e4aa70

Browse files
committed
initial commit CoC API (moved from bitbucket)
1 parent ba80c23 commit 9e4aa70

13 files changed

Lines changed: 5880 additions & 2 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ build/Release
3535
# Dependency directories
3636
node_modules/
3737
jspm_packages/
38+
uploads/
3839

3940
# TypeScript v1 declaration files
4041
typings/

README.md

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,43 @@
1-
# Clock-of-Change-API
2-
nodejs api for Clock of Change
1+
**COC API Server**
2+
3+
the new COC API is written in nodejs on top of express.
4+
All routes reside in /core/restapi.js
5+
6+
**AUTHENTICATION**
7+
8+
to authenticate simply send API-Key in each requests headers
9+
10+
**USAGE:**
11+
12+
if you have nodemon installed from dev dependencies use "npm start"
13+
to run the Server, the default port is 1337.
14+
15+
to ensure emails are working properly make sure to set your smtp credentials in
16+
/core/mailer.js this will use templates from /mails directory.
17+
18+
*DATABASE*
19+
20+
we use mysql for the coc api right now we have 2 tables entries and apikeys
21+
22+
once the server is running you can use the following routes:
23+
24+
GET http://127.0.0.1/cube.php
25+
- return the current count of entries with email_confirmed === 1 && status === 1
26+
- no auth required
27+
- returns the number (we change to json once we can adjust hardware clocks)
28+
GET http://127.0.0.1/entries/verify/:k
29+
- verify an entry with a valid link parameter :k for example http://127.0.0.1/entries/verify/sadSdjsarj3jf3j3wfmwfj3w
30+
- no auth required
31+
- returns {success : true || false, invalidKeyError if key is invalid/used}
32+
POST http://127.0.0.1/entries
33+
- call with body data firstname, lastname, email, country, message, anon (int 0 or 1), image to create a new entry
34+
- requires auth (see **AUTHENTICATION**)
35+
- returns {success : true}
36+
- may return errors mimeError, sizeError, missingFields, fieldErrors, missingImageError
37+
38+
GET http://127.0.0.1/entries
39+
- to get back all entries allowed parameters are limit (10), offset (0) and active (false)
40+
where active will return items which have email_confirmed === 1 AND status === 1
41+
- requires auth
42+
- returns {success : true, results : out, totalCount : results.length, page : offset}
43+
- return {success : false, message : "error"}

core/db.js

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
'use strict';
2+
3+
let mysql = require('mysql'),
4+
moment = require('moment');
5+
6+
// TODO: refactor
7+
let pool = mysql.createPool({
8+
host : process.env.MYSQL_HOST || 'localhost',
9+
user : process.env.MYSQL_USER || '',
10+
password : process.env.MYSQL_PASS || '',
11+
database : process.env.MYSQL_DB || '',
12+
//socketPath : '/var/run/mysqld/mysqld.sock',
13+
connectionLimit : 30,
14+
supportBigNumbers : true
15+
});
16+
17+
exports.toggleEntryStatus = function(id, state, callback){
18+
pool.getConnection(function(err, connection) {
19+
if(err) { console.log(err); callback(true); return; }
20+
// TODO: UPDATE STATUS
21+
// 1 = confirmed | 2 = removed
22+
let sql;
23+
if(state === '1' || state === '2'){
24+
sql = "UPDATE entries SET status = "+state+" WHERE id = "+id;
25+
}else{
26+
callback({}, false);
27+
return;
28+
}
29+
30+
// make the query
31+
connection.query(sql, function(err, results) {
32+
connection.release();
33+
if(err) { callback(results, true); return; }
34+
callback(results, false);
35+
});
36+
});
37+
};
38+
39+
exports.isValidApiKey = function(secret, callback){
40+
pool.getConnection(function(err, connection) {
41+
if(err) { console.log(err); callback(true); return; }
42+
let sql = "SELECT valid from apikeys WHERE secret = '"+secret+"';";
43+
44+
console.log(sql);
45+
46+
// make the query
47+
connection.query(sql, function(err, results) {
48+
connection.release();
49+
if(err) { callback(results, true); return; }
50+
callback(results, false);
51+
});
52+
});
53+
};
54+
55+
exports.getEntries = function(limit, offset, active, callback){
56+
pool.getConnection(function(err, connection) {
57+
if(err) { console.log(err); callback(true); return; }
58+
let sql = '';
59+
if(active === '0'){
60+
sql = "SELECT * FROM entries ORDER BY ID DESC LIMIT "+limit+" OFFSET "+offset+";";
61+
}else{
62+
sql = "SELECT * FROM entries WHERE email_confirmed = 1 AND status = 1 ORDER BY ID DESC LIMIT "+limit+" OFFSET "+offset+";";
63+
}
64+
65+
console.log(sql);
66+
67+
// make the query
68+
connection.query(sql, function(err, results) {
69+
connection.release();
70+
if(err) { callback(results, true); return; }
71+
callback(results, false);
72+
});
73+
});
74+
};
75+
76+
exports.getUserByHash = function(hash, callback){
77+
pool.getConnection(function(err, connection) {
78+
if(err) { console.log(err); callback(true); return; }
79+
let sql = "SELECT email, firstname from entries WHERE confirm_key = '"+hash+"';";
80+
81+
// make the query
82+
connection.query(sql, function(err, results) {
83+
connection.release();
84+
if(err) { callback(results, true); return; }
85+
callback(results, false);
86+
});
87+
});
88+
};
89+
90+
exports.verifyEntry = function(hash, callback){
91+
pool.getConnection(function(err, connection) {
92+
if(err) { console.log(err); callback(true); return; }
93+
let sql = "UPDATE entries set email_confirmed = 1, confirmed_at = "+moment().valueOf()+" WHERE";
94+
sql += " confirm_key = '"+hash+"' AND";
95+
sql += " confirmed_at is null;";
96+
97+
// make the query
98+
connection.query(sql, function(err, results) {
99+
connection.release();
100+
if(err || results.affectedRows < 1) { callback(results, true); return; }
101+
callback(results, false);
102+
});
103+
});
104+
};
105+
106+
exports.getCount = function(callback){
107+
pool.getConnection(function(err, connection) {
108+
if(err) { console.log(err); callback(true); return; }
109+
let sql = "SELECT count(*) as cnt FROM entries WHERE email_confirmed > 0 AND status < 2 AND country != '';";
110+
111+
// make the query
112+
connection.query(sql, function(err, results) {
113+
connection.release();
114+
if(err) { callback(results, true); return; }
115+
callback(results, false);
116+
});
117+
});
118+
};
119+
120+
exports.saveEntry = function(fields, callback){
121+
pool.getConnection(function(err, connection) {
122+
if(err) { console.log(err); callback(true); return; }
123+
let data = prepareEntry(fields);
124+
125+
let sqle = "SELECT count(*) as cnt FROM entries WHERE email = '"+data.email+"';";
126+
connection.query(sqle, function(err, results) {
127+
if(!err) {
128+
if(results[0]['cnt'] > 0){
129+
callback(true);
130+
return;
131+
}else{
132+
let sql = "INSERT INTO entries (firstname, lastname, email, country, message, anon, ipv4, image, created_at, updated_at, confirm_key, beta, newsletter, pax) VALUES (";
133+
sql += "'"+ data.firstname + "', ";
134+
sql += "'"+ data.lastname + "', ";
135+
sql += "'"+ data.email + "', ";
136+
sql += "'"+ data.country + "', ";
137+
sql += "'"+ data.message + "', ";
138+
sql += data.anon + ", ";
139+
sql += "'"+ data.ipv4 + "', ";
140+
sql += "'"+ data.image + "', ";
141+
sql += data.created_at + ", ";
142+
sql += data.updated_at + ", ";
143+
sql += "'"+ data.randomHash + "', ";
144+
sql += data.beta + ", ";
145+
sql += data.newsletter + ", ";
146+
sql += data.pax + ");";
147+
148+
// run the query
149+
connection.query(sql, function(err, results) {
150+
connection.release();
151+
if(err) { callback(true); return; }
152+
callback(false, results);
153+
});
154+
}
155+
}
156+
});
157+
});
158+
};
159+
160+
/*
161+
* most fields get sanitized and escaped by node-mysql
162+
* this function is to prevent application errors
163+
**/
164+
function prepareEntry(data){
165+
let now = moment().valueOf();
166+
167+
data["image"] = data["image"].replace("uploads\\", "");
168+
169+
// set timestamps
170+
data["created_at"] = now;
171+
data["updated_at"] = now;
172+
173+
return data;
174+
}

0 commit comments

Comments
 (0)