Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2e89dc4
Fixes Bug 866832 - Tag Filtering for Make Creation and Updating
cadecairos May 1, 2013
fff74cd
Fix bug 870397 - Add some helper APIs around make results, return dat…
humphd May 9, 2013
6275fb4
Remove things needed for FakeAPI from .npmignore
humphd May 16, 2013
b2fa6f9
Bump version for npm changes
humphd May 16, 2013
5e1cf1c
Remove routes/* from .npmignore needed by FakeAPI, bump version
humphd May 16, 2013
c59fb46
Fixes Bug 873174 - fix bad comparison for application tags
May 16, 2013
f744024
Add callback arg to FakeAPI.stop()
humphd May 16, 2013
b6d323a
0.1.4
jbuck May 17, 2013
fbf33d1
0.1.5
jbuck May 17, 2013
1876164
No bug - Prevent localhost cookies from overwriting each other. r=me
jbuck May 22, 2013
b4a9df7
Fix Bug 875389 - Allow for searching against the MakeAPI w/ contentType
mjschranz May 23, 2013
ca572b4
0.1.6
mjschranz May 23, 2013
97e8713
[#875322] Expose a remixUrl in the makeapi.
ScottDowne May 23, 2013
141951c
[makeapi] v0.1.7
ScottDowne May 23, 2013
f3b5d7c
Fix Bug 876461 - Strip out remixUrl and fix bug with remixedFrom
mjschranz May 27, 2013
2b33f85
Fix Bug 876419 - Search for projects remixed from another project
mjschranz May 27, 2013
7551e3a
0.1.8
mjschranz May 28, 2013
2a87e48
Fix Bug 876407 - Search by username/subdomain, get maker username/sub…
May 27, 2013
6d1cdbd
0.1.9
May 28, 2013
b1362b1
Fix Bug 876527 - Don't overwrite existing make fields on an update, c…
May 28, 2013
c2d0d46
Fix Bug 877213 - Send emailHash for user back with searches
mjschranz May 29, 2013
656d443
Fix Bug 877270 - _id was being removed from make objects
mjschranz May 29, 2013
0f763a0
Fix Bug 876452 - Consumers of the API should be able to access the pr…
mjschranz May 28, 2013
b56801d
Bug 871700 - filter out duplicate tags
May 29, 2013
9b843b2
0.1.10
May 29, 2013
173bc06
Fix Bug 877325 - updatedAt and createdAt weren't being return with ma…
mjschranz May 29, 2013
9ba769a
Fix Bug 877635 - update references to User.subdomain to User.username
May 30, 2013
e3e796b
Fix Bug 878779 - createdAt was defaulting to a date based on when ser…
mjschranz Jun 3, 2013
a479853
Fix Bug 877372 - Add Title and Description as full text searches
mjschranz May 30, 2013
73ebdf8
0.1.11
mjschranz Jun 3, 2013
704815a
Fix Bug 877693 - correct env.sample in README.md
alicoding Jun 4, 2013
038a1c1
Fix Bug 875134 - Make Editor tool for Admin webmaker accounts
May 23, 2013
fbe3950
0.1.12
Jun 4, 2013
27840a3
Removed "locales" from lib/models/make.js
igoryen Jun 3, 2013
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
.gitignore
Gruntfile.js
server.js
lib/*
node_modules/*
public/js/search.js
public/js/README.md
public/js/admin.js
public/js/external/*
public/stylesheets/*
routes/*
views/*
test/*
12 changes: 9 additions & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@ module.exports = function( grunt ) {

csslint: {
files: [
"public/**/*.css"
"public/gallery/**/*.css",
"public/stylesheets/search.css"
]
},
jshint: {
options: {
es5: true,
newcap: false
},
files: [
"Gruntfile.js",
"server.js",
"lib/**/*.js",
"public/**/*.js",
"routes/**/*.js"
"public/js/*.js",
"routes/**/*.js",
"test/**/*.js"
]
}
});
Expand Down
45 changes: 28 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Execute `npm install` in the application directory:
Copy and edit your .env file. -- This should never be committed to the repo. Ensure that you fill in the ALLOWED_USERS variable.

```
cp .env.sample .env
cp env.sample .env
```

#### Running the Services
Expand Down Expand Up @@ -73,21 +73,30 @@ Right now there is a small node app in `test/test-make-client.js` that will requ
<th>POST</th>
<td>/api/make</td>
<td>Create Make</td>
<td> If Post Data is a valid Make, it creates one and returns it with the _id and __v populated.</td>
<td>
If post data contains a valid Make, it creates one and returns it with the _id.
Post Data should be a JSON object specifying the id of the authenticated webmaker creating the Make<br />
<code>{ "maker": "username", make: { ... } } </code>
</td>
<td><strong>Yes</strong></td>
</tr>
<tr>
<th>PUT</th>
<td>/api/make/:id</td>
<td>Update a Make</td>
<td>The Make must already exist and the __v must be the same as the current version on the server. This is an implementation of optimistic locking.</td>
<td>The Make must already exist. This is an implementation of optimistic locking.
Post Data should be a JSON object specifying the id of the authenticated webmaker updating the Make and a flag indicating if the user has admin priveliges.<br />
<code>{ "maker": "username", make: { ... } }
</td>
<td><strong>Yes</strong></td>
</tr>
<tr>
<th>DELETE</th>
<td>/api/make/:id</td>
<td>Deletes a Make</td>
<td>The effect is that of a delete operation, though the Make is actually only marked as deleted using the deletedAt timestamp.</td>
<td>The effect is that of a delete operation, though the Make is actually only marked as deleted using the <code>deletedAt</code> timestamp.
Post Data should be a JSON object specifying the id of the authenticated webmaker deleting the Make and a flag indicating if the user has admin priveliges.<br />
<code>{ "maker": "username" }</td>
<td><strong>Yes</strong></td>
</tr>
<tr>
Expand All @@ -100,27 +109,27 @@ Right now there is a small node app in `test/test-make-client.js` that will requ
</table>


### Example Usage
### Consuming the API

```
jQuery.ajax({
type: "POST",
url: "/api/make",
data: {
"url": "http://thimble.webmadecontent.org/abcd.html",
"contentType": "text/html",
"title": "Animal something-or-other",
"locale": "en_us",
"tags": ["awesome"],
"privateTags": ["webmaker.org:project", "skill:css"],
"description": "This handy HTML template makes it easy to quickly create your own text and image mashup, then publish it for sharing via Facebook, Tumblr or any web page. Your 15 seconds of internet fame await!",
"author": "swex@mozilla.com",
"contentAuthor": "swex@mozilla.com",
"remixedFrom": null,
"published": true
"user": "webmaker@host.com",
"make": {
"url": "http://thimble.webmadecontent.org/abcd.html",
"contentType": "application/x-thimble",
"title": "Animal something-or-other",
"locale": "en_us",
"tags": [ "awesome", "#css", "thimble.webmaker.org:project" ],
"description": "This handy HTML template makes it easy to quickly create your own text and image mashup, then publish it for sharing via Facebook, Tumblr or any web page. Your 15 seconds of internet fame await!",
"author": "swex@mozilla.com",
"remixedFrom": null
}
},
success: function(data, textStatus, jqXHR){
console.log("Post resposne:");
console.log("Post response:");
console.dir(data);
console.log(textStatus);
console.dir(jqXHR);
Expand All @@ -130,6 +139,8 @@ Right now there is a small node app in `test/test-make-client.js` that will requ
}
});
```
A client library has been written to aid in the consumption of this API.
Documentation can be found [here](public/js/README.md)

### Searching Test Ground

Expand Down
21 changes: 14 additions & 7 deletions env.sample
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
# A Secret used to sign Session cookies.
SESSION_SECRET=I wish the people who clean my office at night were invited to our company Christmas party.
export SESSION_SECRET='I wish the people who clean my office at night were invited to our company Christmas party.'

# Port to listen on
PORT=5000
export PORT=5000

# development or production
export NODE_ENV="development"
export NODE_ENV='development'

# URL of the Mongodb instance
MONGO_URL=mongodb://localhost/makeapi
export MONGO_URL='mongodb://localhost/makeapi'

# Where the server is running. Used for test data generating script
HOST='localhost'
export HOST='localhost'

# Host and port for your Elastic search cluster
ELASTIC_SEARCH_URL='http://localhost:9200'
export ELASTIC_SEARCH_URL='http://localhost:9200'

# A List of allowed users for write operations to the database
# List in this format: "user:pass,user2:pass"
# You shouldn't use this username/password combo yourself
ALLOWED_USERS="testuser:password"
export ALLOWED_USERS='testuser:password'

# Persona
export AUDIENCE="http://webmaker.mofostaging.net"

# statsd metrics collection. If the following are left empty, no stats
# will be collected or sent to a server. Only STATSD_HOST and STATSD_PORT
Expand All @@ -28,3 +31,7 @@ ALLOWED_USERS="testuser:password"
export STATSD_HOST=
export STATSD_PORT=
export STATSD_PREFIX=

# This is used to check if a user is an administrator (include user/password)
# in URL. Don't use this username/password combo
export LOGIN_SERVER_URL_WITH_AUTH='http://loginuser:loginpassword@localhost:3000'
4 changes: 4 additions & 0 deletions lib/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
makeAPI: require( "../public/js/make-api.js" ),
fakeAPI: require( "../test/fake/FakeAPI.js" )
};
85 changes: 73 additions & 12 deletions lib/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,84 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

module.exports = function( env ) {

var userList = env.get( "ALLOWED_USERS" ),
qs = require( "querystring" );

userList = qs.parse( userList, ",", ":" );
module.exports = function( loginApi, env ) {
var qs = require( "querystring" ),
userList = qs.parse( env.get( "ALLOWED_USERS" ), ",", ":" ),
tags = require( "./tags" )();

return {
// Use with express.basicAuth middleware
authenticateUser: function( user, pass ) {
for ( var username in userList ) {
if ( userList.hasOwnProperty( username ) ) {
if ( user === username && pass === userList[ username ] ) {
return true;
}
var found = false;
Object.keys( userList ).forEach( function( username ) {
if ( user === username && pass === userList[ username ] ) {
found = true;
}
});
return found;
},
prefixAuth: function( req, res, next ) {

if ( typeof req.body.make === "string" ) {
req.body.make = qs.parse( req.body.make );
}
return false;
var makerID = req.body.maker,
makeTags = req.body.make.tags,
appTags = req.body.make.appTags;

makeTags = typeof makeTags === "string" ? [makeTags] : makeTags;
appTags = typeof appTags === "string" ? [appTags] : appTags;

loginApi.isAdmin( makerID, function( err, isAdmin ) {
if ( err ) {
return res.json( 500, { error: err } );
}

var options = {
maker: makerID,
isAdmin: isAdmin
},
validTags = [];

if ( makeTags ) {
validTags = tags.validateTags( makeTags, options );
}

if ( appTags ) {
validTags = validTags.concat( tags.validateApplicationTags( appTags, req.user ) );
}

req.body.make.tags = validTags;

next();
});
},
adminAuth: function( req, res, next ) {
var email = req.session ? req.session.email : "";
if ( email ) {
loginApi.isAdmin( email, function( err, isAdmin ) {
if ( err || !isAdmin ) {
return res.json( 403, { reason: "forbidden" } );
}
next();
});
} else {
res.redirect( 302, "/login" );
}
},
verifyPersonaLogin: function( err, req, res, email ) {
if ( err ) {
return res.json({ status: "failure", reason: err });
}
loginApi.isAdmin( email, function( error, isAdmin ) {
var out;
if ( error || !isAdmin ) {
out = { status: "failure", reason: error || "you are not authorised to view this page." };
} else {
out = { status: "okay", email: email };
}
res.json(out);
});
}
};
};
29 changes: 16 additions & 13 deletions lib/models/make.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = function( environment, mongoInstance ) {

var mongoosastic = require( "mongoosastic" ),
validate = require( "mongoose-validator" ).validate,
deferred = require( "deferred" ),
env = environment,
url = require( "url" ),
mongoose = mongoInstance,
Expand Down Expand Up @@ -47,13 +48,11 @@ module.exports = function( environment, mongoInstance ) {
title: {
type: String,
es_indexed: true,
required: true,
es_index: "not_analyzed"
required: true
},
description: {
type: String,
es_indexed: true,
es_index: "not_analyzed"
es_indexed: true
},
thumbnail: {
type: String,
Expand All @@ -71,8 +70,7 @@ module.exports = function( environment, mongoInstance ) {
required: true,
validate: validate( "isEmail" ),
es_indexed: true,
es_index: "not_analyzed",
select: false
es_index: "not_analyzed"
},
published: {
type: Boolean,
Expand All @@ -86,11 +84,10 @@ module.exports = function( environment, mongoInstance ) {
es_type: "String"
},
remixedFrom: {
type: Number,
type: String,
"default": null,
es_indexed: true,
es_index: "not_analyzed",
es_type: "long"
es_index: "not_analyzed"
},
createdAt: Timestamp,
updatedAt: Timestamp,
Expand All @@ -102,6 +99,12 @@ module.exports = function( environment, mongoInstance ) {
}
});

schema.set( "toJSON", { virtuals: true } );

schema.virtual( "id" ).get(function() {
return this._id;
});

// Hooks
schema.pre( "save", function ( next ) {
this.updatedAt = Date.now();
Expand All @@ -122,9 +125,9 @@ module.exports = function( environment, mongoInstance ) {
}
});

Make.publicFields = [ "url", "contentType", "locale", "locales",
"title", "description", "author",
"published", "tags", "thumbnail", "email", "remixedFrom" ];

Make.publicFields = [ "url", "contentType", "locale",
"title", "description", "author", "published", "tags",
"thumbnail", "remixedFrom" ];
return Make;
};
Loading