Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
57 changes: 47 additions & 10 deletions lib/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ module.exports = function( makeModel, apiUserModel, env ) {
hawkOptions.port = 443;
}


function doesUserLike( id, likes ) {
var like,
i;
for ( i = likes.length - 1; i >= 0; i-- ) {
like = likes[ i ];
if ( like.userId === id ) {
return like;
function findUserElem( id, array ) {
var elem;
for ( var i = array.length - 1; i >= 0; i-- ) {
elem = array[ i ];
if ( elem.userId === id ) {
return elem;
}
}
return null;
Expand Down Expand Up @@ -150,6 +148,45 @@ module.exports = function( makeModel, apiUserModel, env ) {
next();
});
},
report: function( req, res, next ) {
var make = req.make;
loginApi.getUserByUsername( req.body.maker, function( err, user ) {
if ( err ) {
return next( err );
}
var report = findUserElem( user.id, make.reports );
if ( !report ) {
make.reports.push({
userId: user.id
});
next();
} else {
next({
status: 400,
message: "User already reported this make"
});
}
});
},
cancelReport: function( req, res, next ) {
var make = req.make;

loginApi.getUserByUsername( req.body.maker, function( err, user ) {
if ( err ) {
return next( err );
}
var report = findUserElem( user.id, make.reports );
if ( report ) {
make.reports.splice( make.reports.indexOf( report ), 1 );
next();
} else {
next({
status: 400,
message: "User has not reported this make"
});
}
});
},
fieldFilter: function( req, res, next ) {
var sanitizedUpdate = {};
if ( req.isCollab ) {
Expand All @@ -166,7 +203,7 @@ module.exports = function( makeModel, apiUserModel, env ) {
if ( err ) {
return next( err );
}
var userLike = doesUserLike( user.id, make.likes );
var userLike = findUserElem( user.id, make.likes );
if ( !userLike ) {
make.likes.push({
userId: user.id
Expand All @@ -186,7 +223,7 @@ module.exports = function( makeModel, apiUserModel, env ) {
if ( err ) {
return next( err );
}
var userLike = doesUserLike( user.id, make.likes );
var userLike = findUserElem( user.id, make.likes );
if ( userLike ) {
make.likes.splice( make.likes.indexOf( userLike ), 1 );
next();
Expand Down
16 changes: 12 additions & 4 deletions lib/models/make.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ module.exports = function( environment, mongoInstance ) {
es_type: "long",
es_indexed: true,
es_index: "not_analyzed"
};
},

var likeSchema = new Mongoose.Schema({
reportSchema = new Mongoose.Schema({
userId: Number
}),

likeSchema = new Mongoose.Schema({
userId: Number
});

Expand Down Expand Up @@ -100,6 +104,10 @@ module.exports = function( environment, mongoInstance ) {
es_index: "not_analyzed",
es_type: "String"
},
reports: {
type: [ reportSchema ],
es_indexed: true
},
remixedFrom: {
type: String,
"default": null,
Expand Down Expand Up @@ -140,8 +148,8 @@ module.exports = function( environment, mongoInstance ) {
});

Make.publicFields = [ "url", "contentType", "contenturl", "locale",
"title", "description", "author", "published", "tags",
"likes", "thumbnail", "remixedFrom" ];
"title", "description", "author", "published",
"tags", "thumbnail", "remixedFrom", "likes", "reports" ];

return Make;
};
3 changes: 2 additions & 1 deletion lib/queryBuilder/generators/sort.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ module.exports.VALID_SORT_FIELDS = [
"url",
"createdAt",
"updatedAt",
"likes"
"likes",
"reports"
];

// Generate a regular sort object for a given field
Expand Down
4 changes: 2 additions & 2 deletions lib/queryBuilder/queryTypes/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ module.exports = function( generators ) {
searchQuery.sort = [];
sort.forEach(function( pair ) {
pair = pair.split( "," );
if ( pair[ 0 ] === "likes" ) {
sortObj = generators.sort.generateScriptSort( "doc['likes.userId'].values.length", pair[ 1 ] );
if ( [ "likes", "reports" ].indexOf( pair[ 0 ] ) !== -1 ) {
sortObj = generators.sort.generateScriptSort( "doc['" + pair[ 0 ] + ".userId'].values.length", pair[ 1 ] );
} else {
sortObj = generators.sort.generateRegularSort( pair[ 0 ], pair[ 1 ] );
}
Expand Down
66 changes: 53 additions & 13 deletions public/js/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ document.addEventListener( "DOMContentLoaded", function() {
},
title: function( r, c, val, def, datactx ) {
return '<a href="' + datactx.url + '" target="_blank">' + val + '</a>';
},
reports: function( row, cell, val ) {
return val ? val.length : 0;
},
clearReports: function( row, cell, val, def, datactx ) {
return '<button onclick="clearReports(\'' + datactx.id + '\');" class="delete-reports-btn red-text">Clear</button>';
}
},

Expand Down Expand Up @@ -110,7 +116,7 @@ document.addEventListener( "DOMContentLoaded", function() {
}
],

ADMIN_COL = {
ADMIN_COLS = [{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason behind this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because it's an array?

id: "id",
name: "Del",
cssClass: "delete-col",
Expand All @@ -120,7 +126,19 @@ document.addEventListener( "DOMContentLoaded", function() {
minWidth: 40,
width: 40,
formatter: FORMATTERS.del
};
}, {
id: "clearReports",
name: "Clear Reports",
field: "reports",
width: 115,
formatter: FORMATTERS.clearReports
}, {
id: "reportCount",
name: "Reports",
field: "reports",
width: 75,
formatter: FORMATTERS.reports
}];

if ( isAdmin ) {
COLUMNS = COLUMNS.map(function( item ) {
Expand All @@ -129,7 +147,9 @@ document.addEventListener( "DOMContentLoaded", function() {
}
return item;
});
COLUMNS.unshift( ADMIN_COL );
ADMIN_COLS.forEach( function( col ) {
COLUMNS.unshift( col );
});
}

var escapeMap = {
Expand Down Expand Up @@ -207,9 +227,10 @@ document.addEventListener( "DOMContentLoaded", function() {
currentPage = 1,
totalPages = 1;

function setQuery( type, query ) {
function setQuery( type, query, sort ) {
currentQuery.type = type;
currentQuery.query = query;
currentQuery.sort = sort;
}

function handleMakes( err, data, total, page ) {
Expand Down Expand Up @@ -241,7 +262,6 @@ document.addEventListener( "DOMContentLoaded", function() {
}

function goToPage( num ) {

if ( currentQuery.type && currentQuery.query ) {
if ( currentQuery.type === "tags" ) {
currentQuery.query = trimItems( currentQuery.query.split( "," ) );
Expand All @@ -252,9 +272,11 @@ document.addEventListener( "DOMContentLoaded", function() {
loadingElem.classList.remove( "spin-hidden" );

make.limit( resultsPerPage )
.page( num )
.sortByField( "createdAt", "desc" )
.then(function( err, data, total ) {
.page( num );

make.sortByField( currentQuery.sort, "desc" );

make.then(function( err, data, total ) {
loadingElem.classList.add( "spin-hidden" );
handleMakes( err, data, total, num );
});
Expand Down Expand Up @@ -353,6 +375,9 @@ document.addEventListener( "DOMContentLoaded", function() {
csrf: csrfToken
}),
searchTypeSelector = document.querySelector( "#filter-type" ),
sortByUpdated = document.querySelector( "#sort-by-updated"),
sortByReports = document.querySelector( "#sort-by-report"),
sortByLikes = document.querySelector( "#sort-by-likes" ),
searchValue = document.querySelector( "#search-tag" ),
searchBtn = document.querySelector( "#search" ),
gridArea = document.querySelector( "#data-table-area" ),
Expand All @@ -378,13 +403,24 @@ document.addEventListener( "DOMContentLoaded", function() {
errorElement: errorSpan
});

window.removeClick = function( id, dataViewId ){
window.removeClick = function( id ){
make.remove( id, function( err ) {
if ( err ) {
errorSpan.classList.remove( "hidden" ).textContent( "Error Deleting! " + JSON.stringify( err ) );
errorSpan.removeClass( "hidden" ).html( "Error Deleting! " + JSON.stringify( err ) );
} else {
dataView.deleteItem( id );
grid.invalidate();
grid.render();
}
else {
dataView.deleteItem( dataViewId );
});
};

window.clearReports = function( id ) {
make.update( id, { reports:[] }, function( err, updatedMake ) {
if ( err ) {
errorSpan.removeClass( "hidden" ).html( "Error Deleting! " + JSON.stringify( err ) );
} else {
dataView.updateItem( id, updatedMake );
grid.invalidate();
grid.render();
}
Expand Down Expand Up @@ -440,13 +476,17 @@ document.addEventListener( "DOMContentLoaded", function() {
});

function doSearch() {
pager.setQuery( searchTypeSelector.value, searchValue.value );
var sort = document.querySelector( "input[name=sort-by]:checked" ).value;
pager.setQuery( searchTypeSelector.value, searchValue.value, sort );
errorSpan.classList.add( "hidden" );
errorSpan.textContent = "";
pager.goToPage( 1 );
}

searchBtn.addEventListener( "click", doSearch, false );
sortByReports.addEventListener( "change", doSearch, false );
sortByLikes.addEventListener( "change", doSearch, false );
sortByUpdated.addEventListener( "change", doSearch, false );

// Press enter to search
searchValue.addEventListener( "keypress", function( e ) {
Expand Down
17 changes: 15 additions & 2 deletions public/stylesheets/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@ div.data-table-area {
display: none !important;
}

.delete-make-btn {
width: 30px;
.delete-make-btn,
.delete-reports-btn {
display: block;
margin: 0 auto;
}

.delete-make-btn {
width: 30px;
}

.red-text {
color: #ff0000;
}
Expand Down Expand Up @@ -108,3 +112,12 @@ span.nav-page-total-setting {
span.nav-page-total-setting.selected {
color: #f00;
}

input[type=radio] {
display: inline-block;
float: left;
}

label.sort-label {
display: inline;
}
2 changes: 1 addition & 1 deletion routes/make.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ module.exports = function( makeModel, env ) {
url: source.url,
deletedAt: source.deletedAt,
likes: source.likes,
reports: source.reports,
remixedFrom: source.remixedFrom,
tags: source.tags,
published: source.published,
Expand Down Expand Up @@ -168,7 +169,6 @@ module.exports = function( makeModel, env ) {
});
},
search: function( req, res ) {

if ( !req.query ) {
return searchError( res, "Malformed Request", 400 );
}
Expand Down
4 changes: 3 additions & 1 deletion server.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ if ( env.get( "ENABLE_GELF_LOGS" ) ) {
logger.init();
app.use( logger.middleware() );
} else {
app.use( express.logger() );
app.use( express.logger( "dev" ) );
}

app.use(express.favicon("public/images/favicon.ico", {
Expand Down Expand Up @@ -105,6 +105,8 @@ app.put( "/api/20130724/make/:id", middleware.hawkAuth, Mongo.isDbOnline, middle
app.put( "/api/20130724/make/like/:id", middleware.hawkAuth, Mongo.isDbOnline, middleware.getMake, middleware.like, routes.update );
app.put( "/api/20130724/make/unlike/:id", middleware.hawkAuth, Mongo.isDbOnline, middleware.getMake, middleware.unlike, routes.update );
app.del( "/api/20130724/make/:id", middleware.hawkAuth, Mongo.isDbOnline, middleware.getMake, routes.remove );
app.put( "/api/20130724/make/report/:id", middleware.hawkAuth, Mongo.isDbOnline, middleware.getMake, middleware.report, routes.update );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can file a general bug on this as it's not a huge deal, but all of these routes should actually have Mongo.isDbOnline as their first middleware. In the case of it being down, I imagine we could crash the server at the hawkAuth middleware.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should actually file a bug to remove isDbOnline altogether. If the DB is down, errors retrieving data should be caught by the error handling middleware.

app.put( "/api/20130724/make/cancelReport/:id", middleware.hawkAuth, Mongo.isDbOnline, middleware.getMake, middleware.cancelReport, routes.update );
app.get( "/api/20130724/make/search", Mongo.isDbOnline, middleware.crossOrigin, routes.search );

// 20130724 Admin API routes
Expand Down
11 changes: 11 additions & 0 deletions views/admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@
<input id="search-tag" name="search-tag" title="PROTIP: empty === get all makes" placeholder="empty gets all makes" class="input-large" type="text">
</div>
</div>
<div class="control-group" >
<label class="control-label" for="sort-by-report">Sort By:</label>
<div class="controls">
<input id="sort-by-updated" value="updatedAt" name="sort-by" title="Select to sort by last updated time" type="radio" checked>
<label for="sort-by-updated" class="sort-label">&nbsp;Updated At</label><br />
<input id="sort-by-report" value="reports" name="sort-by" title="Select to sort bycreation most reports" type="radio">
<label for="sort-by-report" class="sort-label">&nbsp;Report Count</label><br />
<input id="sort-by-likes" value="likes" name="sort-by" title="Select to sort by total like count per make" type="radio">
<label for="sort-by-likes" class="sort-label">&nbsp;Like Count</label>
</div>
</div>
<div class="control-group">
<label class="control-label" for="search"></label>
<div class="controls">
Expand Down