Skip to content
32 changes: 26 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,22 @@
"npm": false,
"gittip": "bevry",
"flattr": "344188/balupton-on-Flattr",
"paypal": "QB8GQPZAH84N6"
"bugs": {
"url": "https://github.com/Docport/inlinegui/issues"
},
"dependencies": {
"docpad": "~6.78.0",
"express": "~3.4.0",
"mongodb": "~1.3.0",
"levelup": "~0.18.0",
"leveldown": "~0.10.0",
"bcrypt": "~0.7.0",
"validator": "~1.5.0"
},
"keywords": [
"docpad-plugin",
"docpad",
"gui",
"cms",
"devDependencies": {
"docpad": "~6.78.0"
}
}
"inline",
"contenteditable"
],
Expand Down Expand Up @@ -77,4 +86,15 @@
"scripts": {
"start": "node ./node_modules/docpad/bin/docpad run --port 9779"
}
{
"name": "inlinegui",
"version": "0.1.0",
"description": "An Inline GUI/CMS for any backend",
"main": "docpad.coffee",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node docpad.coffee"
},
"repository": {
"type": "git",
}
126 changes: 126 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
var express = require('express');
var bodyParser = require('body-parser');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var path = require('path');
var fs = require('fs');

// Database setup
var levelup = require('levelup');
var dbPath = process.env.DB_PATH || './db';
var db = levelup(dbPath);

var app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(session({
secret: process.env.SESSION_SECRET || 'inlinegui-secret',
resave: false,
saveUninitialized: true
}));

// Serve static files from src/files
app.use(express.static(path.join(__dirname, 'src', 'files')));

// API Routes

// Get current user
app.get('/api/user', function(req, res) {
if (req.session.user) {
res.json({ success: true, user: req.session.user });
} else {
res.json({ success: false, user: null });
}
});

// Create or update user (from Persona login)
app.post('/api/user', function(req, res) {
var userData = req.body;

if (!userData.email) {
return res.status(400).json({ success: false, error: 'Email is required' });
}

var user = {
email: userData.email,
name: userData.name || '',
createdAt: new Date().toISOString()
};

// Check if user exists
db.get('user:' + user.email, function(err, existing) {
if (existing) {
// Update existing user
var existingUser = JSON.parse(existing);
user.name = userData.name || existingUser.name || '';
user.createdAt = existingUser.createdAt || user.createdAt;
}

db.put('user:' + user.email, JSON.stringify(user), function(err) {
if (err) {
return res.status(500).json({ success: false, error: 'Failed to save user' });
}

req.session.user = user;
res.json({ success: true, user: user });
});
});
});

// Login user
app.post('/api/login', function(req, res) {
var email = req.body.email;
var name = req.body.name || '';

if (!email) {
return res.status(400).json({ success: false, error: 'Email is required' });
}

var user = {
email: email,
name: name,
lastLoginAt: new Date().toISOString()
};

db.get('user:' + email, function(err, existing) {
if (existing) {
var existingUser = JSON.parse(existing);
user.name = name || existingUser.name || '';
user.createdAt = existingUser.createdAt;
}

db.put('user:' + email, JSON.stringify(user), function(err) {
if (err) {
return res.status(500).json({ success: false, error: 'Failed to save user' });
}

req.session.user = user;
res.json({ success: true, user: user });
});
});
});

// Logout user
app.post('/api/logout', function(req, res) {
req.session.destroy();
res.json({ success: true });
});

// Serve login page
app.get('/login', function(req, res) {
res.sendFile(path.join(__dirname, 'src', 'files', 'login.html'));
});

// Default: serve index
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'src', 'files', 'index.html'));
});

var port = process.env.PORT || 3000;
app.listen(port, function() {
console.log('InlineGUI server listening on port ' + port);
});

module.exports = app;
182 changes: 182 additions & 0 deletions shanaboo_solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
```diff
--- a/package.json
+++ b/package.json
@@ -0,0 +0,0
-{
- "name": "inlinegui",
- "version": "0.1.0",
- "description": "An Inline GUI/CMS for any backend",
- "main": "docpad.coffee",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/Docport/inlinegui.git"
- },
- "author": "",
- "license": "MIT"
-}
+{
+ "name": "inlinegui",
+ "version": "0.1.0",
+ "description": "An Inline GUI/CMS for any backend",
+ "main": "docpad.coffee",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Docport/inlinegui.git"
+ },
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "levelup": "~0.18.0",
+ "leveldown": "~0.10.0",
+ "express": "~3.4.0",
+ "body-parser": "~1.0.0"
+ }
+}
--- a/docpad.coffee
+++ b/docpad.coffee
@@ -0,0 +0,0
-# Docpad Configuration File
-# http://docpad.org/docs/config
-
-docpadConfig = {
- # ...
-}
-
-# Export our DocPad Configuration
-module.exports = docpadConfig
+# Docpad Configuration File
+# http://docpad.org/docs/config
+
+levelup = require('levelup')
+path = require('path')
+
+# Initialize LevelUP database
+dbPath = path.join(__dirname, 'data', 'users')
+db = levelup(dbPath)
+
+docpadConfig = {
+ # Server configuration for Persona authentication and user management
+ serverExtend:
+ server: (server, express, docpadInstance) ->
+ # Parse JSON body
+ express.use(express.bodyParser())
+
+ # Serve static files for login page
+ express.use('/login', express.static(path.join(__dirname, 'src', 'files', 'login')))
+
+ # Persona verification endpoint
+ express.post('/auth/persona/verify', (req, res) ->
+ assertion = req.body.assertion
+
+ # Verify assertion with Mozilla Persona
+ https = require('https')
+ querystring = require('querystring')
+
+ data = querystring.stringify({
+ assertion: assertion,
+ audience: req.headers.host
+ })
+
+ options = {
+ host: 'verifier.login.persona.org',
+ path: '/verify',
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ 'Content-Length': Buffer.byteLength(data)
+ }
+ }
+
+ verifyReq = https.request(options, (verifyRes) ->
+ body = ''
+ verifyRes.on('data', (chunk) -> body += chunk)
+ verifyRes.on('end', () ->
+ try
+ response = JSON.parse(body)
+
+ if response.status is 'okay'
+ email = response.email
+
+ # Check if user exists, create if not
+ db.get(email, (err, userData) ->
+ if err and err.notFound
+ # Create new user
+ user = {
+ email: email,
+ name: email.split('@')[0],
+ createdAt: new Date().toISOString()
+ }
+
+ db.put(email, JSON.stringify(user), (err) ->
+ if err
+ res.status(500).json({status: 'error', message: 'Failed to save user'})
+ return
+
+ req.session ?= {}
+ req.session.user = user
+ res.json({status: 'okay', email: email, name: user.name})
+ )
+ else if err
+ res.status(500).json({status: 'error', message: 'Database error'})
+ else
+ # User exists, update session
+ user = JSON.parse(userData)
+ req.session ?= {}
+ req.session.user = user
+ res.json({status: 'okay', email: email, name: user.name})
+ )
+ else
+ res.status(403).json({status: 'failure', reason: response.reason})
+ catch e
+ res.status(500).json({status: 'error', message: 'Invalid response from verifier'})
+ )
+ )
+
+ verifyReq.on('error', (err) ->
+ res.status(500).json({status: 'error', message: 'Verification request failed'})
+ )
+
+ verifyReq.write(data)
+ verifyReq.end()
+ )
+
+ # Update user info endpoint
+ express.post('/api/user/update', (req, res) ->
+ email = req.body.email
+ name = req.body.name
+
+ if not email or not name
+ res.status(400).json({status: 'error', message: 'Email and name required'})
+ return
+
+ db.get(email, (err, userData) ->
+ if err and err.notFound
+ res.status(404).json({status: 'error', message: 'User not found'})
+ else if err
+ res.status(500).json({status: 'error', message: 'Database error'})
+ else
+ user = JSON.parse(userData)
+ user.name = name
+
+ db.put(email, JSON.stringify(user), (err) ->
+ if err
+ res.status(500).json({status: 'error', message: 'Failed to update user'})
+ return
+
+ req.session ?= {}
+ req.session.user = user
+ res.json({status: 'okay', user: user})
+ )
+ )
+ )
+
+ # Get current user endpoint
+ express.get('/api/user/current', (req, res) ->
+ if req.session?.user
+ res.json({status: 'okay', user: req.session.user})