diff --git a/nodebb b/nodebb index ded766b51e..880afdf563 100755 --- a/nodebb +++ b/nodebb @@ -20,7 +20,7 @@ case "$1" in echo "Launching NodeBB in \"development\" mode." echo "To run the production build of NodeBB, please use \"forever\"." echo "More Information: https://github.com/designcreateplay/NodeBB/wiki/How-to-run-NodeBB" - NODE_ENV=development supervisor --extensions 'node|js|tpl' -- app $1 + NODE_ENV=development supervisor -q --extensions 'node|js|tpl' -- app $1 ;; language) diff --git a/public/language/en/user.json b/public/language/en/user.json index 1b58f198de..caa4a59b57 100644 --- a/public/language/en/user.json +++ b/public/language/en/user.json @@ -32,5 +32,8 @@ "show_email": "Show My Email", "has_no_follower": "This user doesn't have any followers :(", - "follows_no_one": "This user isn't following anyone :(" + "follows_no_one": "This user isn't following anyone :(", + + "email_hidden": "Email Hidden", + "hidden": "hidden" } diff --git a/public/src/forum/admin/categories.js b/public/src/forum/admin/categories.js index 0874ffa878..73eafde5df 100644 --- a/public/src/forum/admin/categories.js +++ b/public/src/forum/admin/categories.js @@ -211,6 +211,7 @@ define(['uploader'], function(uploader) { var modal = $('#category-permissions-modal'), searchEl = modal.find('#permission-search'), resultsEl = modal.find('.search-results'), + groupsResultsEl = modal.find('.groups-results'), searchDelay; searchEl.off().on('keyup', function() { @@ -263,6 +264,40 @@ define(['uploader'], function(uploader) { searchEl.keyup(); }); + // User Groups and privileges + socket.emit('api:admin.categories.groupsearch', cid, function(err, results) { + var groupsFrag = document.createDocumentFragment(), + liEl = document.createElement('li'); + var numResults = results.length, + resultObj; + + for(var x=0;x<numResults;x++) { + resultObj = results[x]; + liEl.setAttribute('data-gid', resultObj.gid); + liEl.innerHTML = '<div class="pull-right">' + + '<div class="btn-group">' + + '<button type="button" data-gpriv="+gr" class="btn btn-default' + (resultObj.privileges['+gr'] ? ' active' : '') + '">Read</button>' + + '<button type="button" data-gpriv="+gw" class="btn btn-default' + (resultObj.privileges['+gw'] ? ' active' : '') + '">Write</button>' + + '</div>' + + '</div>' + + ' '+resultObj.name; + + groupsFrag.appendChild(liEl.cloneNode(true)); + } + + groupsResultsEl.html(groupsFrag); + }); + + groupsResultsEl.off().on('click', '[data-gpriv]', function(e) { + var btnEl = $(this), + gid = btnEl.parents('li[data-gid]').attr('data-gid'), + privilege = this.getAttribute('data-gpriv'); + e.preventDefault(); + socket.emit('api:admin.categories.setGroupPrivilege', cid, gid, privilege, !btnEl.hasClass('active'), function(err, privileges) { + btnEl.toggleClass('active', privileges[privilege]); + }); + }) + modal.modal(); }; @@ -312,4 +347,4 @@ define(['uploader'], function(uploader) { }; return Categories; -}); \ No newline at end of file +}); diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 3a47ce901c..424d12db2c 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -102,7 +102,7 @@ define(function() { var loadingEl = document.getElementById('categories-loading'); if (loadingEl) { - socket.once('api:categories.get', function(data) { + socket.emit('api:categories.get', function(data) { // Render categories var categoriesFrag = document.createDocumentFragment(), categoryEl = document.createElement('li'), @@ -172,7 +172,6 @@ define(function() { } }); }); - socket.emit('api:categories.get'); } }); } @@ -483,7 +482,21 @@ define(function() { adjust_rep(-1, data.pid, data.uid); }); - socket.on('event:new_post', createNewPosts); + socket.on('event:new_post', function(data) { + var posts = data.posts; + for (var p in posts) { + if (posts.hasOwnProperty(p)) { + var post = posts[p], + postcount = jQuery('.user_postcount_' + post.uid), + ptotal = parseInt(postcount.html(), 10); + + ptotal += 1; + postcount.html(ptotal); + } + } + + createNewPosts(data); + }); socket.on('event:topic_deleted', function(data) { if (data.tid === tid && data.status === 'ok') { @@ -802,7 +815,7 @@ define(function() { pagination.parentNode.style.display = 'block'; progressBarContainer.css('display', ''); - + if (scrollTop < jQuery('.posts > .post-row:first-child').height() && Topic.postCount > 1) { localStorage.removeItem("topic:" + tid + ":bookmark"); pagination.innerHTML = '1 out of ' + Topic.postCount; diff --git a/public/templates/account.tpl b/public/templates/account.tpl index 200fd854c2..571bb2ddd2 100644 --- a/public/templates/account.tpl +++ b/public/templates/account.tpl @@ -20,34 +20,51 @@ <span class="label label-danger">[[user:banned]]</span> </div> <!-- ENDIF banned --> + <div> + <a id="chat-btn" href="#" class="btn btn-default hide">Chat</a> + </div> <div id="user-actions"> - <a id="follow-btn" href="#" class="btn btn-default">Follow</a> - <a id="unfollow-btn" href="#" class="btn btn-default">Unfollow</a> + <a id="follow-btn" href="#" class="btn btn-default hide">Follow</a> + <a id="unfollow-btn" href="#" class="btn btn-default hide">Unfollow</a> </div> </div> <div class="col-md-4"> <div class="inline-block"> <div class="account-bio-block"> - <span class="account-bio-label">[[user:email]]</span><i class="fa fa-eye-slash {emailClass}" title="Email hidden"></i> + <span class="account-bio-label">[[user:email]]</span><i class="fa fa-eye-slash {emailClass}" title="[[user:email_hidden]]"></i> + <!-- IF email --> <span>{email}</span> + <!-- ELSE --> + <i class="fa fa-eye-slash" title="[[user:email_hidden]]"></i> [[user:hidden]] + <!-- ENDIF email --> <br/> + + <!-- IF fullname --> <span class="account-bio-label">[[user:fullname]]</span> <span>{fullname}</span> <br/> + <!-- ENDIF fullname --> + <!-- IF website --> <span class="account-bio-label">[[user:website]]</span> <span><a href="{website}">{websiteName}</a></span> <br/> + <!-- ENDIF website --> + <!-- IF location --> <span class="account-bio-label">[[user:location]]</span> <span>{location}</span> <br/> + <!-- ENDIF location --> + <!-- IF age --> <span class="account-bio-label">[[user:age]]</span> <span>{age}</span> <br/> + <!-- ENDIF age --> + <hr/> <span class="account-bio-label">[[user:joined]]</span> <span class="timeago" title="{joindate}"></span> @@ -74,10 +91,12 @@ <br/> <hr/> + <!-- IF signature --> <span class="account-bio-label">[[user:signature]]</span> <div class="post-signature"> <span id='signature'>{signature}</span> </div> + <!-- ENDIF signature --> </div> </div> </div> diff --git a/public/templates/admin/categories.tpl b/public/templates/admin/categories.tpl index a8da120e82..9651b387a9 100644 --- a/public/templates/admin/categories.tpl +++ b/public/templates/admin/categories.tpl @@ -154,12 +154,18 @@ </div> </form> <ul class="search-results"></ul> + <form role="form"> + <div class="form-group"> + <label for="permission-group-pick">User Groups</label> + </div> + </form> + <ul class="groups-results"></ul> </div> </div> </div> </div> <div id="icons" style="display:none;"><div class="icon-container"><div class="row fa-icons"> - <div class="col-md-3"><i class="fa fa-glass"></i></div><div class="col-md-3"><i class="fa fa-music"></i></div><div class="col-md-3"><i class="fa fa-search"></i></div><div class="col-md-3"><i class="fa fa-envelope-o"></i></div><div class="col-md-3"><i class="fa fa-heart"></i></div><div class="col-md-3"><i class="fa fa-star"></i></div><div class="col-md-3"><i class="fa fa-star-o"></i></div><div class="col-md-3"><i class="fa fa-user"></i></div><div class="col-md-3"><i class="fa fa-film"></i></div><div class="col-md-3"><i class="fa fa-th-large"></i></div><div class="col-md-3"><i class="fa fa-th"></i></div><div class="col-md-3"><i class="fa fa-th-list"></i></div><div class="col-md-3"><i class="fa fa-check"></i></div><div class="col-md-3"><i class="fa fa-times"></i></div><div class="col-md-3"><i class="fa fa-search-plus"></i></div><div class="col-md-3"><i class="fa fa-search-minus"></i></div><div class="col-md-3"><i class="fa fa-power-off"></i></div><div class="col-md-3"><i class="fa fa-signal"></i></div><div class="col-md-3"><i class="fa fa-cog"></i></div><div class="col-md-3"><i class="fa fa-trash-o"></i></div><div class="col-md-3"><i class="fa fa-home"></i></div><div class="col-md-3"><i class="fa fa-file-o"></i></div><div class="col-md-3"><i class="fa fa-clock-o"></i></div><div class="col-md-3"><i class="fa fa-road"></i></div><div class="col-md-3"><i class="fa fa-download"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-o-down"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-o-up"></i></div><div class="col-md-3"><i class="fa fa-inbox"></i></div><div class="col-md-3"><i class="fa fa-play-circle-o"></i></div><div class="col-md-3"><i class="fa fa-repeat"></i></div><div class="col-md-3"><i class="fa fa-refresh"></i></div><div class="col-md-3"><i class="fa fa-list-alt"></i></div><div class="col-md-3"><i class="fa fa-lock"></i></div><div class="col-md-3"><i class="fa fa-flag"></i></div><div class="col-md-3"><i class="fa fa-headphones"></i></div><div class="col-md-3"><i class="fa fa-volume-off"></i></div><div class="col-md-3"><i class="fa fa-volume-down"></i></div><div class="col-md-3"><i class="fa fa-volume-up"></i></div><div class="col-md-3"><i class="fa fa-qrcode"></i></div><div class="col-md-3"><i class="fa fa-barcode"></i></div><div class="col-md-3"><i class="fa fa-tag"></i></div><div class="col-md-3"><i class="fa fa-tags"></i></div><div class="col-md-3"><i class="fa fa-book"></i></div><div class="col-md-3"><i class="fa fa-bookmark"></i></div><div class="col-md-3"><i class="fa fa-print"></i></div><div class="col-md-3"><i class="fa fa-camera"></i></div><div class="col-md-3"><i class="fa fa-font"></i></div><div class="col-md-3"><i class="fa fa-bold"></i></div><div class="col-md-3"><i class="fa fa-italic"></i></div><div class="col-md-3"><i class="fa fa-text-height"></i></div><div class="col-md-3"><i class="fa fa-text-width"></i></div><div class="col-md-3"><i class="fa fa-align-left"></i></div><div class="col-md-3"><i class="fa fa-align-center"></i></div><div class="col-md-3"><i class="fa fa-align-right"></i></div><div class="col-md-3"><i class="fa fa-align-justify"></i></div><div class="col-md-3"><i class="fa fa-list"></i></div><div class="col-md-3"><i class="fa fa-outdent"></i></div><div class="col-md-3"><i class="fa fa-indent"></i></div><div class="col-md-3"><i class="fa fa-video-camera"></i></div><div class="col-md-3"><i class="fa fa-picture-o"></i></div><div class="col-md-3"><i class="fa fa-pencil"></i></div><div class="col-md-3"><i class="fa fa-map-marker"></i></div><div class="col-md-3"><i class="fa fa-adjust"></i></div><div class="col-md-3"><i class="fa fa-tint"></i></div><div class="col-md-3"><i class="fa fa-pencil-square-o"></i></div><div class="col-md-3"><i class="fa fa-share-square-o"></i></div><div class="col-md-3"><i class="fa fa-check-square-o"></i></div><div class="col-md-3"><i class="fa fa-arrows"></i></div><div class="col-md-3"><i class="fa fa-step-backward"></i></div><div class="col-md-3"><i class="fa fa-fast-backward"></i></div><div class="col-md-3"><i class="fa fa-backward"></i></div><div class="col-md-3"><i class="fa fa-play"></i></div><div class="col-md-3"><i class="fa fa-pause"></i></div><div class="col-md-3"><i class="fa fa-stop"></i></div><div class="col-md-3"><i class="fa fa-forward"></i></div><div class="col-md-3"><i class="fa fa-fast-forward"></i></div><div class="col-md-3"><i class="fa fa-step-forward"></i></div><div class="col-md-3"><i class="fa fa-eject"></i></div><div class="col-md-3"><i class="fa fa-chevron-left"></i></div><div class="col-md-3"><i class="fa fa-chevron-right"></i></div><div class="col-md-3"><i class="fa fa-plus-circle"></i></div><div class="col-md-3"><i class="fa fa-minus-circle"></i></div><div class="col-md-3"><i class="fa fa-times-circle"></i></div><div class="col-md-3"><i class="fa fa-check-circle"></i></div><div class="col-md-3"><i class="fa fa-question-circle"></i></div><div class="col-md-3"><i class="fa fa-info-circle"></i></div><div class="col-md-3"><i class="fa fa-crosshairs"></i></div><div class="col-md-3"><i class="fa fa-times-circle-o"></i></div><div class="col-md-3"><i class="fa fa-check-circle-o"></i></div><div class="col-md-3"><i class="fa fa-ban"></i></div><div class="col-md-3"><i class="fa fa-arrow-left"></i></div><div class="col-md-3"><i class="fa fa-arrow-right"></i></div><div class="col-md-3"><i class="fa fa-arrow-up"></i></div><div class="col-md-3"><i class="fa fa-arrow-down"></i></div><div class="col-md-3"><i class="fa fa-share"></i></div><div class="col-md-3"><i class="fa fa-expand"></i></div><div class="col-md-3"><i class="fa fa-compress"></i></div><div class="col-md-3"><i class="fa fa-plus"></i></div><div class="col-md-3"><i class="fa fa-minus"></i></div><div class="col-md-3"><i class="fa fa-asterisk"></i></div><div class="col-md-3"><i class="fa fa-exclamation-circle"></i></div><div class="col-md-3"><i class="fa fa-gift"></i></div><div class="col-md-3"><i class="fa fa-leaf"></i></div><div class="col-md-3"><i class="fa fa-fire"></i></div><div class="col-md-3"><i class="fa fa-eye"></i></div><div class="col-md-3"><i class="fa fa-eye-slash"></i></div><div class="col-md-3"><i class="fa fa-exclamation-triangle"></i></div><div class="col-md-3"><i class="fa fa-plane"></i></div><div class="col-md-3"><i class="fa fa-calendar"></i></div><div class="col-md-3"><i class="fa fa-random"></i></div><div class="col-md-3"><i class="fa fa-comment"></i></div><div class="col-md-3"><i class="fa fa-magnet"></i></div><div class="col-md-3"><i class="fa fa-chevron-up"></i></div><div class="col-md-3"><i class="fa fa-chevron-down"></i></div><div class="col-md-3"><i class="fa fa-retweet"></i></div><div class="col-md-3"><i class="fa fa-shopping-cart"></i></div><div class="col-md-3"><i class="fa fa-folder"></i></div><div class="col-md-3"><i class="fa fa-folder-open"></i></div><div class="col-md-3"><i class="fa fa-arrows-v"></i></div><div class="col-md-3"><i class="fa fa-arrows-h"></i></div><div class="col-md-3"><i class="fa fa-bar-chart-o"></i></div><div class="col-md-3"><i class="fa fa-twitter-square"></i></div><div class="col-md-3"><i class="fa fa-facebook-square"></i></div><div class="col-md-3"><i class="fa fa-camera-retro"></i></div><div class="col-md-3"><i class="fa fa-key"></i></div><div class="col-md-3"><i class="fa fa-cogs"></i></div><div class="col-md-3"><i class="fa fa-comments"></i></div><div class="col-md-3"><i class="fa fa-thumbs-o-up"></i></div><div class="col-md-3"><i class="fa fa-thumbs-o-down"></i></div><div class="col-md-3"><i class="fa fa-star-half"></i></div><div class="col-md-3"><i class="fa fa-heart-o"></i></div><div class="col-md-3"><i class="fa fa-sign-out"></i></div><div class="col-md-3"><i class="fa fa-linkedin-square"></i></div><div class="col-md-3"><i class="fa fa-thumb-tack"></i></div><div class="col-md-3"><i class="fa fa-external-link"></i></div><div class="col-md-3"><i class="fa fa-sign-in"></i></div><div class="col-md-3"><i class="fa fa-trophy"></i></div><div class="col-md-3"><i class="fa fa-github-square"></i></div><div class="col-md-3"><i class="fa fa-upload"></i></div><div class="col-md-3"><i class="fa fa-lemon-o"></i></div><div class="col-md-3"><i class="fa fa-phone"></i></div><div class="col-md-3"><i class="fa fa-square-o"></i></div><div class="col-md-3"><i class="fa fa-bookmark-o"></i></div><div class="col-md-3"><i class="fa fa-phone-square"></i></div><div class="col-md-3"><i class="fa fa-twitter"></i></div><div class="col-md-3"><i class="fa fa-facebook"></i></div><div class="col-md-3"><i class="fa fa-github"></i></div><div class="col-md-3"><i class="fa fa-unlock"></i></div><div class="col-md-3"><i class="fa fa-credit-card"></i></div><div class="col-md-3"><i class="fa fa-rss"></i></div><div class="col-md-3"><i class="fa fa-hdd-o"></i></div><div class="col-md-3"><i class="fa fa-bullhorn"></i></div><div class="col-md-3"><i class="fa fa-bell"></i></div><div class="col-md-3"><i class="fa fa-certificate"></i></div><div class="col-md-3"><i class="fa fa-hand-o-right"></i></div><div class="col-md-3"><i class="fa fa-hand-o-left"></i></div><div class="col-md-3"><i class="fa fa-hand-o-up"></i></div><div class="col-md-3"><i class="fa fa-hand-o-down"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-left"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-right"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-up"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-down"></i></div><div class="col-md-3"><i class="fa fa-globe"></i></div><div class="col-md-3"><i class="fa fa-wrench"></i></div><div class="col-md-3"><i class="fa fa-tasks"></i></div><div class="col-md-3"><i class="fa fa-filter"></i></div><div class="col-md-3"><i class="fa fa-briefcase"></i></div><div class="col-md-3"><i class="fa fa-arrows-alt"></i></div><div class="col-md-3"><i class="fa fa-users"></i></div><div class="col-md-3"><i class="fa fa-link"></i></div><div class="col-md-3"><i class="fa fa-cloud"></i></div><div class="col-md-3"><i class="fa fa-flask"></i></div><div class="col-md-3"><i class="fa fa-scissors"></i></div><div class="col-md-3"><i class="fa fa-files-o"></i></div><div class="col-md-3"><i class="fa fa-paperclip"></i></div><div class="col-md-3"><i class="fa fa-floppy-o"></i></div><div class="col-md-3"><i class="fa fa-square"></i></div><div class="col-md-3"><i class="fa fa-bars"></i></div><div class="col-md-3"><i class="fa fa-list-ul"></i></div><div class="col-md-3"><i class="fa fa-list-ol"></i></div><div class="col-md-3"><i class="fa fa-strikethrough"></i></div><div class="col-md-3"><i class="fa fa-underline"></i></div><div class="col-md-3"><i class="fa fa-table"></i></div><div class="col-md-3"><i class="fa fa-magic"></i></div><div class="col-md-3"><i class="fa fa-truck"></i></div><div class="col-md-3"><i class="fa fa-pinterest"></i></div><div class="col-md-3"><i class="fa fa-pinterest-square"></i></div><div class="col-md-3"><i class="fa fa-google-plus-square"></i></div><div class="col-md-3"><i class="fa fa-google-plus"></i></div><div class="col-md-3"><i class="fa fa-money"></i></div><div class="col-md-3"><i class="fa fa-caret-down"></i></div><div class="col-md-3"><i class="fa fa-caret-up"></i></div><div class="col-md-3"><i class="fa fa-caret-left"></i></div><div class="col-md-3"><i class="fa fa-caret-right"></i></div><div class="col-md-3"><i class="fa fa-columns"></i></div><div class="col-md-3"><i class="fa fa-sort"></i></div><div class="col-md-3"><i class="fa fa-sort-asc"></i></div><div class="col-md-3"><i class="fa fa-sort-desc"></i></div><div class="col-md-3"><i class="fa fa-envelope"></i></div><div class="col-md-3"><i class="fa fa-linkedin"></i></div><div class="col-md-3"><i class="fa fa-undo"></i></div><div class="col-md-3"><i class="fa fa-gavel"></i></div><div class="col-md-3"><i class="fa fa-tachometer"></i></div><div class="col-md-3"><i class="fa fa-comment-o"></i></div><div class="col-md-3"><i class="fa fa-comments-o"></i></div><div class="col-md-3"><i class="fa fa-bolt"></i></div><div class="col-md-3"><i class="fa fa-sitemap"></i></div><div class="col-md-3"><i class="fa fa-umbrella"></i></div><div class="col-md-3"><i class="fa fa-clipboard"></i></div><div class="col-md-3"><i class="fa fa-lightbulb-o"></i></div><div class="col-md-3"><i class="fa fa-exchange"></i></div><div class="col-md-3"><i class="fa fa-cloud-download"></i></div><div class="col-md-3"><i class="fa fa-cloud-upload"></i></div><div class="col-md-3"><i class="fa fa-user-md"></i></div><div class="col-md-3"><i class="fa fa-stethoscope"></i></div><div class="col-md-3"><i class="fa fa-suitcase"></i></div><div class="col-md-3"><i class="fa fa-bell-o"></i></div><div class="col-md-3"><i class="fa fa-coffee"></i></div><div class="col-md-3"><i class="fa fa-cutlery"></i></div><div class="col-md-3"><i class="fa fa-file-text-o"></i></div><div class="col-md-3"><i class="fa fa-building-o"></i></div><div class="col-md-3"><i class="fa fa-hospital-o"></i></div><div class="col-md-3"><i class="fa fa-ambulance"></i></div><div class="col-md-3"><i class="fa fa-medkit"></i></div><div class="col-md-3"><i class="fa fa-fighter-jet"></i></div><div class="col-md-3"><i class="fa fa-beer"></i></div><div class="col-md-3"><i class="fa fa-h-square"></i></div><div class="col-md-3"><i class="fa fa-plus-square"></i></div><div class="col-md-3"><i class="fa fa-angle-double-left"></i></div><div class="col-md-3"><i class="fa fa-angle-double-right"></i></div><div class="col-md-3"><i class="fa fa-angle-double-up"></i></div><div class="col-md-3"><i class="fa fa-angle-double-down"></i></div><div class="col-md-3"><i class="fa fa-angle-left"></i></div><div class="col-md-3"><i class="fa fa-angle-right"></i></div><div class="col-md-3"><i class="fa fa-angle-up"></i></div><div class="col-md-3"><i class="fa fa-angle-down"></i></div><div class="col-md-3"><i class="fa fa-desktop"></i></div><div class="col-md-3"><i class="fa fa-laptop"></i></div><div class="col-md-3"><i class="fa fa-tablet"></i></div><div class="col-md-3"><i class="fa fa-mobile"></i></div><div class="col-md-3"><i class="fa fa-circle-o"></i></div><div class="col-md-3"><i class="fa fa-quote-left"></i></div><div class="col-md-3"><i class="fa fa-quote-right"></i></div><div class="col-md-3"><i class="fa fa-spinner"></i></div><div class="col-md-3"><i class="fa fa-circle"></i></div><div class="col-md-3"><i class="fa fa-reply"></i></div><div class="col-md-3"><i class="fa fa-github-alt"></i></div><div class="col-md-3"><i class="fa fa-folder-o"></i></div><div class="col-md-3"><i class="fa fa-folder-open-o"></i></div><div class="col-md-3"><i class="fa fa-smile-o"></i></div><div class="col-md-3"><i class="fa fa-frown-o"></i></div><div class="col-md-3"><i class="fa fa-meh-o"></i></div><div class="col-md-3"><i class="fa fa-gamepad"></i></div><div class="col-md-3"><i class="fa fa-keyboard-o"></i></div><div class="col-md-3"><i class="fa fa-flag-o"></i></div><div class="col-md-3"><i class="fa fa-flag-checkered"></i></div><div class="col-md-3"><i class="fa fa-terminal"></i></div><div class="col-md-3"><i class="fa fa-code"></i></div><div class="col-md-3"><i class="fa fa-reply-all"></i></div><div class="col-md-3"><i class="fa fa-mail-reply-all"></i></div><div class="col-md-3"><i class="fa fa-star-half-o"></i></div><div class="col-md-3"><i class="fa fa-location-arrow"></i></div><div class="col-md-3"><i class="fa fa-crop"></i></div><div class="col-md-3"><i class="fa fa-code-fork"></i></div><div class="col-md-3"><i class="fa fa-chain-broken"></i></div><div class="col-md-3"><i class="fa fa-question"></i></div><div class="col-md-3"><i class="fa fa-info"></i></div><div class="col-md-3"><i class="fa fa-exclamation"></i></div><div class="col-md-3"><i class="fa fa-superscript"></i></div><div class="col-md-3"><i class="fa fa-subscript"></i></div><div class="col-md-3"><i class="fa fa-eraser"></i></div><div class="col-md-3"><i class="fa fa-puzzle-piece"></i></div><div class="col-md-3"><i class="fa fa-microphone"></i></div><div class="col-md-3"><i class="fa fa-microphone-slash"></i></div><div class="col-md-3"><i class="fa fa-shield"></i></div><div class="col-md-3"><i class="fa fa-calendar-o"></i></div><div class="col-md-3"><i class="fa fa-fire-extinguisher"></i></div><div class="col-md-3"><i class="fa fa-rocket"></i></div><div class="col-md-3"><i class="fa fa-maxcdn"></i></div><div class="col-md-3"><i class="fa fa-chevron-circle-left"></i></div><div class="col-md-3"><i class="fa fa-chevron-circle-right"></i></div><div class="col-md-3"><i class="fa fa-chevron-circle-up"></i></div><div class="col-md-3"><i class="fa fa-chevron-circle-down"></i></div><div class="col-md-3"><i class="fa fa-html5"></i></div><div class="col-md-3"><i class="fa fa-css3"></i></div><div class="col-md-3"><i class="fa fa-anchor"></i></div><div class="col-md-3"><i class="fa fa-unlock-alt"></i></div><div class="col-md-3"><i class="fa fa-bullseye"></i></div><div class="col-md-3"><i class="fa fa-ellipsis-h"></i></div><div class="col-md-3"><i class="fa fa-ellipsis-v"></i></div><div class="col-md-3"><i class="fa fa-rss-square"></i></div><div class="col-md-3"><i class="fa fa-play-circle"></i></div><div class="col-md-3"><i class="fa fa-ticket"></i></div><div class="col-md-3"><i class="fa fa-minus-square"></i></div><div class="col-md-3"><i class="fa fa-minus-square-o"></i></div><div class="col-md-3"><i class="fa fa-level-up"></i></div><div class="col-md-3"><i class="fa fa-level-down"></i></div><div class="col-md-3"><i class="fa fa-check-square"></i></div><div class="col-md-3"><i class="fa fa-pencil-square"></i></div><div class="col-md-3"><i class="fa fa-external-link-square"></i></div><div class="col-md-3"><i class="fa fa-share-square"></i></div><div class="col-md-3"><i class="fa fa-compass"></i></div><div class="col-md-3"><i class="fa fa-caret-square-o-down"></i></div><div class="col-md-3"><i class="fa fa-caret-square-o-up"></i></div><div class="col-md-3"><i class="fa fa-caret-square-o-right"></i></div><div class="col-md-3"><i class="fa fa-eur"></i></div><div class="col-md-3"><i class="fa fa-gbp"></i></div><div class="col-md-3"><i class="fa fa-usd"></i></div><div class="col-md-3"><i class="fa fa-inr"></i></div><div class="col-md-3"><i class="fa fa-jpy"></i></div><div class="col-md-3"><i class="fa fa-rub"></i></div><div class="col-md-3"><i class="fa fa-krw"></i></div><div class="col-md-3"><i class="fa fa-btc"></i></div><div class="col-md-3"><i class="fa fa-file"></i></div><div class="col-md-3"><i class="fa fa-file-text"></i></div><div class="col-md-3"><i class="fa fa-sort-alpha-asc"></i></div><div class="col-md-3"><i class="fa fa-sort-alpha-desc"></i></div><div class="col-md-3"><i class="fa fa-sort-amount-asc"></i></div><div class="col-md-3"><i class="fa fa-sort-amount-desc"></i></div><div class="col-md-3"><i class="fa fa-sort-numeric-asc"></i></div><div class="col-md-3"><i class="fa fa-sort-numeric-desc"></i></div><div class="col-md-3"><i class="fa fa-thumbs-up"></i></div><div class="col-md-3"><i class="fa fa-thumbs-down"></i></div><div class="col-md-3"><i class="fa fa-youtube-square"></i></div><div class="col-md-3"><i class="fa fa-youtube"></i></div><div class="col-md-3"><i class="fa fa-xing"></i></div><div class="col-md-3"><i class="fa fa-xing-square"></i></div><div class="col-md-3"><i class="fa fa-youtube-play"></i></div><div class="col-md-3"><i class="fa fa-dropbox"></i></div><div class="col-md-3"><i class="fa fa-stack-overflow"></i></div><div class="col-md-3"><i class="fa fa-instagram"></i></div><div class="col-md-3"><i class="fa fa-flickr"></i></div><div class="col-md-3"><i class="fa fa-adn"></i></div><div class="col-md-3"><i class="fa fa-bitbucket"></i></div><div class="col-md-3"><i class="fa fa-bitbucket-square"></i></div><div class="col-md-3"><i class="fa fa-tumblr"></i></div><div class="col-md-3"><i class="fa fa-tumblr-square"></i></div><div class="col-md-3"><i class="fa fa-long-arrow-down"></i></div><div class="col-md-3"><i class="fa fa-long-arrow-up"></i></div><div class="col-md-3"><i class="fa fa-long-arrow-left"></i></div><div class="col-md-3"><i class="fa fa-long-arrow-right"></i></div><div class="col-md-3"><i class="fa fa-apple"></i></div><div class="col-md-3"><i class="fa fa-windows"></i></div><div class="col-md-3"><i class="fa fa-android"></i></div><div class="col-md-3"><i class="fa fa-linux"></i></div><div class="col-md-3"><i class="fa fa-dribbble"></i></div><div class="col-md-3"><i class="fa fa-skype"></i></div><div class="col-md-3"><i class="fa fa-foursquare"></i></div><div class="col-md-3"><i class="fa fa-trello"></i></div><div class="col-md-3"><i class="fa fa-female"></i></div><div class="col-md-3"><i class="fa fa-male"></i></div><div class="col-md-3"><i class="fa fa-gittip"></i></div><div class="col-md-3"><i class="fa fa-sun-o"></i></div><div class="col-md-3"><i class="fa fa-moon-o"></i></div><div class="col-md-3"><i class="fa fa-archive"></i></div><div class="col-md-3"><i class="fa fa-bug"></i></div><div class="col-md-3"><i class="fa fa-vk"></i></div><div class="col-md-3"><i class="fa fa-weibo"></i></div><div class="col-md-3"><i class="fa fa-renren"></i></div><div class="col-md-3"><i class="fa fa-pagelines"></i></div><div class="col-md-3"><i class="fa fa-stack-exchange"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-o-right"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-o-left"></i></div><div class="col-md-3"><i class="fa fa-caret-square-o-left"></i></div><div class="col-md-3"><i class="fa fa-dot-circle-o"></i></div><div class="col-md-3"><i class="fa fa-wheelchair"></i></div><div class="col-md-3"><i class="fa fa-vimeo-square"></i></div><div class="col-md-3"><i class="fa fa-try"></i></div><div class="col-md-3"><i class="fa fa-plus-square-o"></i></div> + <div class="col-md-3"><i class="fa fa-doesnt-exist"></i></div><div class="col-md-3"><i class="fa fa-glass"></i></div><div class="col-md-3"><i class="fa fa-music"></i></div><div class="col-md-3"><i class="fa fa-search"></i></div><div class="col-md-3"><i class="fa fa-envelope-o"></i></div><div class="col-md-3"><i class="fa fa-heart"></i></div><div class="col-md-3"><i class="fa fa-star"></i></div><div class="col-md-3"><i class="fa fa-star-o"></i></div><div class="col-md-3"><i class="fa fa-user"></i></div><div class="col-md-3"><i class="fa fa-film"></i></div><div class="col-md-3"><i class="fa fa-th-large"></i></div><div class="col-md-3"><i class="fa fa-th"></i></div><div class="col-md-3"><i class="fa fa-th-list"></i></div><div class="col-md-3"><i class="fa fa-check"></i></div><div class="col-md-3"><i class="fa fa-times"></i></div><div class="col-md-3"><i class="fa fa-search-plus"></i></div><div class="col-md-3"><i class="fa fa-search-minus"></i></div><div class="col-md-3"><i class="fa fa-power-off"></i></div><div class="col-md-3"><i class="fa fa-signal"></i></div><div class="col-md-3"><i class="fa fa-cog"></i></div><div class="col-md-3"><i class="fa fa-trash-o"></i></div><div class="col-md-3"><i class="fa fa-home"></i></div><div class="col-md-3"><i class="fa fa-file-o"></i></div><div class="col-md-3"><i class="fa fa-clock-o"></i></div><div class="col-md-3"><i class="fa fa-road"></i></div><div class="col-md-3"><i class="fa fa-download"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-o-down"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-o-up"></i></div><div class="col-md-3"><i class="fa fa-inbox"></i></div><div class="col-md-3"><i class="fa fa-play-circle-o"></i></div><div class="col-md-3"><i class="fa fa-repeat"></i></div><div class="col-md-3"><i class="fa fa-refresh"></i></div><div class="col-md-3"><i class="fa fa-list-alt"></i></div><div class="col-md-3"><i class="fa fa-lock"></i></div><div class="col-md-3"><i class="fa fa-flag"></i></div><div class="col-md-3"><i class="fa fa-headphones"></i></div><div class="col-md-3"><i class="fa fa-volume-off"></i></div><div class="col-md-3"><i class="fa fa-volume-down"></i></div><div class="col-md-3"><i class="fa fa-volume-up"></i></div><div class="col-md-3"><i class="fa fa-qrcode"></i></div><div class="col-md-3"><i class="fa fa-barcode"></i></div><div class="col-md-3"><i class="fa fa-tag"></i></div><div class="col-md-3"><i class="fa fa-tags"></i></div><div class="col-md-3"><i class="fa fa-book"></i></div><div class="col-md-3"><i class="fa fa-bookmark"></i></div><div class="col-md-3"><i class="fa fa-print"></i></div><div class="col-md-3"><i class="fa fa-camera"></i></div><div class="col-md-3"><i class="fa fa-font"></i></div><div class="col-md-3"><i class="fa fa-bold"></i></div><div class="col-md-3"><i class="fa fa-italic"></i></div><div class="col-md-3"><i class="fa fa-text-height"></i></div><div class="col-md-3"><i class="fa fa-text-width"></i></div><div class="col-md-3"><i class="fa fa-align-left"></i></div><div class="col-md-3"><i class="fa fa-align-center"></i></div><div class="col-md-3"><i class="fa fa-align-right"></i></div><div class="col-md-3"><i class="fa fa-align-justify"></i></div><div class="col-md-3"><i class="fa fa-list"></i></div><div class="col-md-3"><i class="fa fa-outdent"></i></div><div class="col-md-3"><i class="fa fa-indent"></i></div><div class="col-md-3"><i class="fa fa-video-camera"></i></div><div class="col-md-3"><i class="fa fa-picture-o"></i></div><div class="col-md-3"><i class="fa fa-pencil"></i></div><div class="col-md-3"><i class="fa fa-map-marker"></i></div><div class="col-md-3"><i class="fa fa-adjust"></i></div><div class="col-md-3"><i class="fa fa-tint"></i></div><div class="col-md-3"><i class="fa fa-pencil-square-o"></i></div><div class="col-md-3"><i class="fa fa-share-square-o"></i></div><div class="col-md-3"><i class="fa fa-check-square-o"></i></div><div class="col-md-3"><i class="fa fa-arrows"></i></div><div class="col-md-3"><i class="fa fa-step-backward"></i></div><div class="col-md-3"><i class="fa fa-fast-backward"></i></div><div class="col-md-3"><i class="fa fa-backward"></i></div><div class="col-md-3"><i class="fa fa-play"></i></div><div class="col-md-3"><i class="fa fa-pause"></i></div><div class="col-md-3"><i class="fa fa-stop"></i></div><div class="col-md-3"><i class="fa fa-forward"></i></div><div class="col-md-3"><i class="fa fa-fast-forward"></i></div><div class="col-md-3"><i class="fa fa-step-forward"></i></div><div class="col-md-3"><i class="fa fa-eject"></i></div><div class="col-md-3"><i class="fa fa-chevron-left"></i></div><div class="col-md-3"><i class="fa fa-chevron-right"></i></div><div class="col-md-3"><i class="fa fa-plus-circle"></i></div><div class="col-md-3"><i class="fa fa-minus-circle"></i></div><div class="col-md-3"><i class="fa fa-times-circle"></i></div><div class="col-md-3"><i class="fa fa-check-circle"></i></div><div class="col-md-3"><i class="fa fa-question-circle"></i></div><div class="col-md-3"><i class="fa fa-info-circle"></i></div><div class="col-md-3"><i class="fa fa-crosshairs"></i></div><div class="col-md-3"><i class="fa fa-times-circle-o"></i></div><div class="col-md-3"><i class="fa fa-check-circle-o"></i></div><div class="col-md-3"><i class="fa fa-ban"></i></div><div class="col-md-3"><i class="fa fa-arrow-left"></i></div><div class="col-md-3"><i class="fa fa-arrow-right"></i></div><div class="col-md-3"><i class="fa fa-arrow-up"></i></div><div class="col-md-3"><i class="fa fa-arrow-down"></i></div><div class="col-md-3"><i class="fa fa-share"></i></div><div class="col-md-3"><i class="fa fa-expand"></i></div><div class="col-md-3"><i class="fa fa-compress"></i></div><div class="col-md-3"><i class="fa fa-plus"></i></div><div class="col-md-3"><i class="fa fa-minus"></i></div><div class="col-md-3"><i class="fa fa-asterisk"></i></div><div class="col-md-3"><i class="fa fa-exclamation-circle"></i></div><div class="col-md-3"><i class="fa fa-gift"></i></div><div class="col-md-3"><i class="fa fa-leaf"></i></div><div class="col-md-3"><i class="fa fa-fire"></i></div><div class="col-md-3"><i class="fa fa-eye"></i></div><div class="col-md-3"><i class="fa fa-eye-slash"></i></div><div class="col-md-3"><i class="fa fa-exclamation-triangle"></i></div><div class="col-md-3"><i class="fa fa-plane"></i></div><div class="col-md-3"><i class="fa fa-calendar"></i></div><div class="col-md-3"><i class="fa fa-random"></i></div><div class="col-md-3"><i class="fa fa-comment"></i></div><div class="col-md-3"><i class="fa fa-magnet"></i></div><div class="col-md-3"><i class="fa fa-chevron-up"></i></div><div class="col-md-3"><i class="fa fa-chevron-down"></i></div><div class="col-md-3"><i class="fa fa-retweet"></i></div><div class="col-md-3"><i class="fa fa-shopping-cart"></i></div><div class="col-md-3"><i class="fa fa-folder"></i></div><div class="col-md-3"><i class="fa fa-folder-open"></i></div><div class="col-md-3"><i class="fa fa-arrows-v"></i></div><div class="col-md-3"><i class="fa fa-arrows-h"></i></div><div class="col-md-3"><i class="fa fa-bar-chart-o"></i></div><div class="col-md-3"><i class="fa fa-twitter-square"></i></div><div class="col-md-3"><i class="fa fa-facebook-square"></i></div><div class="col-md-3"><i class="fa fa-camera-retro"></i></div><div class="col-md-3"><i class="fa fa-key"></i></div><div class="col-md-3"><i class="fa fa-cogs"></i></div><div class="col-md-3"><i class="fa fa-comments"></i></div><div class="col-md-3"><i class="fa fa-thumbs-o-up"></i></div><div class="col-md-3"><i class="fa fa-thumbs-o-down"></i></div><div class="col-md-3"><i class="fa fa-star-half"></i></div><div class="col-md-3"><i class="fa fa-heart-o"></i></div><div class="col-md-3"><i class="fa fa-sign-out"></i></div><div class="col-md-3"><i class="fa fa-linkedin-square"></i></div><div class="col-md-3"><i class="fa fa-thumb-tack"></i></div><div class="col-md-3"><i class="fa fa-external-link"></i></div><div class="col-md-3"><i class="fa fa-sign-in"></i></div><div class="col-md-3"><i class="fa fa-trophy"></i></div><div class="col-md-3"><i class="fa fa-github-square"></i></div><div class="col-md-3"><i class="fa fa-upload"></i></div><div class="col-md-3"><i class="fa fa-lemon-o"></i></div><div class="col-md-3"><i class="fa fa-phone"></i></div><div class="col-md-3"><i class="fa fa-square-o"></i></div><div class="col-md-3"><i class="fa fa-bookmark-o"></i></div><div class="col-md-3"><i class="fa fa-phone-square"></i></div><div class="col-md-3"><i class="fa fa-twitter"></i></div><div class="col-md-3"><i class="fa fa-facebook"></i></div><div class="col-md-3"><i class="fa fa-github"></i></div><div class="col-md-3"><i class="fa fa-unlock"></i></div><div class="col-md-3"><i class="fa fa-credit-card"></i></div><div class="col-md-3"><i class="fa fa-rss"></i></div><div class="col-md-3"><i class="fa fa-hdd-o"></i></div><div class="col-md-3"><i class="fa fa-bullhorn"></i></div><div class="col-md-3"><i class="fa fa-bell"></i></div><div class="col-md-3"><i class="fa fa-certificate"></i></div><div class="col-md-3"><i class="fa fa-hand-o-right"></i></div><div class="col-md-3"><i class="fa fa-hand-o-left"></i></div><div class="col-md-3"><i class="fa fa-hand-o-up"></i></div><div class="col-md-3"><i class="fa fa-hand-o-down"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-left"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-right"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-up"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-down"></i></div><div class="col-md-3"><i class="fa fa-globe"></i></div><div class="col-md-3"><i class="fa fa-wrench"></i></div><div class="col-md-3"><i class="fa fa-tasks"></i></div><div class="col-md-3"><i class="fa fa-filter"></i></div><div class="col-md-3"><i class="fa fa-briefcase"></i></div><div class="col-md-3"><i class="fa fa-arrows-alt"></i></div><div class="col-md-3"><i class="fa fa-users"></i></div><div class="col-md-3"><i class="fa fa-link"></i></div><div class="col-md-3"><i class="fa fa-cloud"></i></div><div class="col-md-3"><i class="fa fa-flask"></i></div><div class="col-md-3"><i class="fa fa-scissors"></i></div><div class="col-md-3"><i class="fa fa-files-o"></i></div><div class="col-md-3"><i class="fa fa-paperclip"></i></div><div class="col-md-3"><i class="fa fa-floppy-o"></i></div><div class="col-md-3"><i class="fa fa-square"></i></div><div class="col-md-3"><i class="fa fa-bars"></i></div><div class="col-md-3"><i class="fa fa-list-ul"></i></div><div class="col-md-3"><i class="fa fa-list-ol"></i></div><div class="col-md-3"><i class="fa fa-strikethrough"></i></div><div class="col-md-3"><i class="fa fa-underline"></i></div><div class="col-md-3"><i class="fa fa-table"></i></div><div class="col-md-3"><i class="fa fa-magic"></i></div><div class="col-md-3"><i class="fa fa-truck"></i></div><div class="col-md-3"><i class="fa fa-pinterest"></i></div><div class="col-md-3"><i class="fa fa-pinterest-square"></i></div><div class="col-md-3"><i class="fa fa-google-plus-square"></i></div><div class="col-md-3"><i class="fa fa-google-plus"></i></div><div class="col-md-3"><i class="fa fa-money"></i></div><div class="col-md-3"><i class="fa fa-caret-down"></i></div><div class="col-md-3"><i class="fa fa-caret-up"></i></div><div class="col-md-3"><i class="fa fa-caret-left"></i></div><div class="col-md-3"><i class="fa fa-caret-right"></i></div><div class="col-md-3"><i class="fa fa-columns"></i></div><div class="col-md-3"><i class="fa fa-sort"></i></div><div class="col-md-3"><i class="fa fa-sort-asc"></i></div><div class="col-md-3"><i class="fa fa-sort-desc"></i></div><div class="col-md-3"><i class="fa fa-envelope"></i></div><div class="col-md-3"><i class="fa fa-linkedin"></i></div><div class="col-md-3"><i class="fa fa-undo"></i></div><div class="col-md-3"><i class="fa fa-gavel"></i></div><div class="col-md-3"><i class="fa fa-tachometer"></i></div><div class="col-md-3"><i class="fa fa-comment-o"></i></div><div class="col-md-3"><i class="fa fa-comments-o"></i></div><div class="col-md-3"><i class="fa fa-bolt"></i></div><div class="col-md-3"><i class="fa fa-sitemap"></i></div><div class="col-md-3"><i class="fa fa-umbrella"></i></div><div class="col-md-3"><i class="fa fa-clipboard"></i></div><div class="col-md-3"><i class="fa fa-lightbulb-o"></i></div><div class="col-md-3"><i class="fa fa-exchange"></i></div><div class="col-md-3"><i class="fa fa-cloud-download"></i></div><div class="col-md-3"><i class="fa fa-cloud-upload"></i></div><div class="col-md-3"><i class="fa fa-user-md"></i></div><div class="col-md-3"><i class="fa fa-stethoscope"></i></div><div class="col-md-3"><i class="fa fa-suitcase"></i></div><div class="col-md-3"><i class="fa fa-bell-o"></i></div><div class="col-md-3"><i class="fa fa-coffee"></i></div><div class="col-md-3"><i class="fa fa-cutlery"></i></div><div class="col-md-3"><i class="fa fa-file-text-o"></i></div><div class="col-md-3"><i class="fa fa-building-o"></i></div><div class="col-md-3"><i class="fa fa-hospital-o"></i></div><div class="col-md-3"><i class="fa fa-ambulance"></i></div><div class="col-md-3"><i class="fa fa-medkit"></i></div><div class="col-md-3"><i class="fa fa-fighter-jet"></i></div><div class="col-md-3"><i class="fa fa-beer"></i></div><div class="col-md-3"><i class="fa fa-h-square"></i></div><div class="col-md-3"><i class="fa fa-plus-square"></i></div><div class="col-md-3"><i class="fa fa-angle-double-left"></i></div><div class="col-md-3"><i class="fa fa-angle-double-right"></i></div><div class="col-md-3"><i class="fa fa-angle-double-up"></i></div><div class="col-md-3"><i class="fa fa-angle-double-down"></i></div><div class="col-md-3"><i class="fa fa-angle-left"></i></div><div class="col-md-3"><i class="fa fa-angle-right"></i></div><div class="col-md-3"><i class="fa fa-angle-up"></i></div><div class="col-md-3"><i class="fa fa-angle-down"></i></div><div class="col-md-3"><i class="fa fa-desktop"></i></div><div class="col-md-3"><i class="fa fa-laptop"></i></div><div class="col-md-3"><i class="fa fa-tablet"></i></div><div class="col-md-3"><i class="fa fa-mobile"></i></div><div class="col-md-3"><i class="fa fa-circle-o"></i></div><div class="col-md-3"><i class="fa fa-quote-left"></i></div><div class="col-md-3"><i class="fa fa-quote-right"></i></div><div class="col-md-3"><i class="fa fa-spinner"></i></div><div class="col-md-3"><i class="fa fa-circle"></i></div><div class="col-md-3"><i class="fa fa-reply"></i></div><div class="col-md-3"><i class="fa fa-github-alt"></i></div><div class="col-md-3"><i class="fa fa-folder-o"></i></div><div class="col-md-3"><i class="fa fa-folder-open-o"></i></div><div class="col-md-3"><i class="fa fa-smile-o"></i></div><div class="col-md-3"><i class="fa fa-frown-o"></i></div><div class="col-md-3"><i class="fa fa-meh-o"></i></div><div class="col-md-3"><i class="fa fa-gamepad"></i></div><div class="col-md-3"><i class="fa fa-keyboard-o"></i></div><div class="col-md-3"><i class="fa fa-flag-o"></i></div><div class="col-md-3"><i class="fa fa-flag-checkered"></i></div><div class="col-md-3"><i class="fa fa-terminal"></i></div><div class="col-md-3"><i class="fa fa-code"></i></div><div class="col-md-3"><i class="fa fa-reply-all"></i></div><div class="col-md-3"><i class="fa fa-mail-reply-all"></i></div><div class="col-md-3"><i class="fa fa-star-half-o"></i></div><div class="col-md-3"><i class="fa fa-location-arrow"></i></div><div class="col-md-3"><i class="fa fa-crop"></i></div><div class="col-md-3"><i class="fa fa-code-fork"></i></div><div class="col-md-3"><i class="fa fa-chain-broken"></i></div><div class="col-md-3"><i class="fa fa-question"></i></div><div class="col-md-3"><i class="fa fa-info"></i></div><div class="col-md-3"><i class="fa fa-exclamation"></i></div><div class="col-md-3"><i class="fa fa-superscript"></i></div><div class="col-md-3"><i class="fa fa-subscript"></i></div><div class="col-md-3"><i class="fa fa-eraser"></i></div><div class="col-md-3"><i class="fa fa-puzzle-piece"></i></div><div class="col-md-3"><i class="fa fa-microphone"></i></div><div class="col-md-3"><i class="fa fa-microphone-slash"></i></div><div class="col-md-3"><i class="fa fa-shield"></i></div><div class="col-md-3"><i class="fa fa-calendar-o"></i></div><div class="col-md-3"><i class="fa fa-fire-extinguisher"></i></div><div class="col-md-3"><i class="fa fa-rocket"></i></div><div class="col-md-3"><i class="fa fa-maxcdn"></i></div><div class="col-md-3"><i class="fa fa-chevron-circle-left"></i></div><div class="col-md-3"><i class="fa fa-chevron-circle-right"></i></div><div class="col-md-3"><i class="fa fa-chevron-circle-up"></i></div><div class="col-md-3"><i class="fa fa-chevron-circle-down"></i></div><div class="col-md-3"><i class="fa fa-html5"></i></div><div class="col-md-3"><i class="fa fa-css3"></i></div><div class="col-md-3"><i class="fa fa-anchor"></i></div><div class="col-md-3"><i class="fa fa-unlock-alt"></i></div><div class="col-md-3"><i class="fa fa-bullseye"></i></div><div class="col-md-3"><i class="fa fa-ellipsis-h"></i></div><div class="col-md-3"><i class="fa fa-ellipsis-v"></i></div><div class="col-md-3"><i class="fa fa-rss-square"></i></div><div class="col-md-3"><i class="fa fa-play-circle"></i></div><div class="col-md-3"><i class="fa fa-ticket"></i></div><div class="col-md-3"><i class="fa fa-minus-square"></i></div><div class="col-md-3"><i class="fa fa-minus-square-o"></i></div><div class="col-md-3"><i class="fa fa-level-up"></i></div><div class="col-md-3"><i class="fa fa-level-down"></i></div><div class="col-md-3"><i class="fa fa-check-square"></i></div><div class="col-md-3"><i class="fa fa-pencil-square"></i></div><div class="col-md-3"><i class="fa fa-external-link-square"></i></div><div class="col-md-3"><i class="fa fa-share-square"></i></div><div class="col-md-3"><i class="fa fa-compass"></i></div><div class="col-md-3"><i class="fa fa-caret-square-o-down"></i></div><div class="col-md-3"><i class="fa fa-caret-square-o-up"></i></div><div class="col-md-3"><i class="fa fa-caret-square-o-right"></i></div><div class="col-md-3"><i class="fa fa-eur"></i></div><div class="col-md-3"><i class="fa fa-gbp"></i></div><div class="col-md-3"><i class="fa fa-usd"></i></div><div class="col-md-3"><i class="fa fa-inr"></i></div><div class="col-md-3"><i class="fa fa-jpy"></i></div><div class="col-md-3"><i class="fa fa-rub"></i></div><div class="col-md-3"><i class="fa fa-krw"></i></div><div class="col-md-3"><i class="fa fa-btc"></i></div><div class="col-md-3"><i class="fa fa-file"></i></div><div class="col-md-3"><i class="fa fa-file-text"></i></div><div class="col-md-3"><i class="fa fa-sort-alpha-asc"></i></div><div class="col-md-3"><i class="fa fa-sort-alpha-desc"></i></div><div class="col-md-3"><i class="fa fa-sort-amount-asc"></i></div><div class="col-md-3"><i class="fa fa-sort-amount-desc"></i></div><div class="col-md-3"><i class="fa fa-sort-numeric-asc"></i></div><div class="col-md-3"><i class="fa fa-sort-numeric-desc"></i></div><div class="col-md-3"><i class="fa fa-thumbs-up"></i></div><div class="col-md-3"><i class="fa fa-thumbs-down"></i></div><div class="col-md-3"><i class="fa fa-youtube-square"></i></div><div class="col-md-3"><i class="fa fa-youtube"></i></div><div class="col-md-3"><i class="fa fa-xing"></i></div><div class="col-md-3"><i class="fa fa-xing-square"></i></div><div class="col-md-3"><i class="fa fa-youtube-play"></i></div><div class="col-md-3"><i class="fa fa-dropbox"></i></div><div class="col-md-3"><i class="fa fa-stack-overflow"></i></div><div class="col-md-3"><i class="fa fa-instagram"></i></div><div class="col-md-3"><i class="fa fa-flickr"></i></div><div class="col-md-3"><i class="fa fa-adn"></i></div><div class="col-md-3"><i class="fa fa-bitbucket"></i></div><div class="col-md-3"><i class="fa fa-bitbucket-square"></i></div><div class="col-md-3"><i class="fa fa-tumblr"></i></div><div class="col-md-3"><i class="fa fa-tumblr-square"></i></div><div class="col-md-3"><i class="fa fa-long-arrow-down"></i></div><div class="col-md-3"><i class="fa fa-long-arrow-up"></i></div><div class="col-md-3"><i class="fa fa-long-arrow-left"></i></div><div class="col-md-3"><i class="fa fa-long-arrow-right"></i></div><div class="col-md-3"><i class="fa fa-apple"></i></div><div class="col-md-3"><i class="fa fa-windows"></i></div><div class="col-md-3"><i class="fa fa-android"></i></div><div class="col-md-3"><i class="fa fa-linux"></i></div><div class="col-md-3"><i class="fa fa-dribbble"></i></div><div class="col-md-3"><i class="fa fa-skype"></i></div><div class="col-md-3"><i class="fa fa-foursquare"></i></div><div class="col-md-3"><i class="fa fa-trello"></i></div><div class="col-md-3"><i class="fa fa-female"></i></div><div class="col-md-3"><i class="fa fa-male"></i></div><div class="col-md-3"><i class="fa fa-gittip"></i></div><div class="col-md-3"><i class="fa fa-sun-o"></i></div><div class="col-md-3"><i class="fa fa-moon-o"></i></div><div class="col-md-3"><i class="fa fa-archive"></i></div><div class="col-md-3"><i class="fa fa-bug"></i></div><div class="col-md-3"><i class="fa fa-vk"></i></div><div class="col-md-3"><i class="fa fa-weibo"></i></div><div class="col-md-3"><i class="fa fa-renren"></i></div><div class="col-md-3"><i class="fa fa-pagelines"></i></div><div class="col-md-3"><i class="fa fa-stack-exchange"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-o-right"></i></div><div class="col-md-3"><i class="fa fa-arrow-circle-o-left"></i></div><div class="col-md-3"><i class="fa fa-caret-square-o-left"></i></div><div class="col-md-3"><i class="fa fa-dot-circle-o"></i></div><div class="col-md-3"><i class="fa fa-wheelchair"></i></div><div class="col-md-3"><i class="fa fa-vimeo-square"></i></div><div class="col-md-3"><i class="fa fa-try"></i></div><div class="col-md-3"><i class="fa fa-plus-square-o"></i></div> </div></div></div> -</div> \ No newline at end of file +</div> diff --git a/public/templates/login.tpl b/public/templates/login.tpl index cad99bc5a4..233986f339 100644 --- a/public/templates/login.tpl +++ b/public/templates/login.tpl @@ -40,7 +40,8 @@ </div> <div class="form-group"> <div class="col-lg-offset-2 col-lg-10"> - <button class="btn btn-primary" id="login" type="submit">[[login:login]]</button> <a id="reset-link" class="hide" href="/reset">[[login:forgot_password]]</a> + <hr /> + <button class="btn btn-primary btn-lg btn-block" id="login" type="submit">[[login:login]]</button> <a id="reset-link" class="hide" href="/reset">[[login:forgot_password]]</a> </div> </div> <input type="hidden" name="_csrf" value="{token}" id="csrf-token" /> diff --git a/public/templates/search.tpl b/public/templates/search.tpl index 9bea91611c..0f2ad27a30 100644 --- a/public/templates/search.tpl +++ b/public/templates/search.tpl @@ -15,41 +15,54 @@ <div class="category search"> <div class="{show_results}"> - <ul id="topics-container" data-search-query="{search_query}"> <h3>[[topic:topics]]</h3> + + <!-- IF topic_matches --> + <small>{topic_matches} result(s) matching "{search_query}"</small> + <!-- ENDIF topic_matches --> <div class="alert alert-info {show_no_topics}">[[topic:no_topics_found]]</div> - <!-- BEGIN topics --> - <a href="../../topic/{topics.slug}" id="tid-{topics.tid}"> + + <ul id="topics-container" data-search-query="{search_query}"> + + <!-- BEGIN topics --> <li class="category-item"> - <div> - <div class="col-md-12 img-thumbnail"> - <div class="search-result-post"> - <img src="{topics.teaser_userpicture}" /> - <strong>{topics.teaser_username}</strong>: <span class="search-result-text">{topics.title}</span> - </div> + <a href="../../topic/{topics.slug}" id="tid-{topics.tid}"> + <div> + <div class="col-md-12 img-thumbnail"> + <div class="search-result-post"> + <img src="{topics.teaser_userpicture}" /> + <strong>{topics.teaser_username}</strong>: <span class="search-result-text">{topics.title}</span> + </div> + </div> </div> - </div> + </a> </li> - </a> - <!-- END topics --> + <!-- END topics --> + </ul> + <h3>Posts</h3> + <!-- IF post_matches --> + <small>{post_matches} result(s) matching "{search_query}"</small> + <!-- ENDIF post_matches --> <div class="alert alert-info {show_no_posts}">No posts found!</div> - <!-- BEGIN posts --> - <a href="../../topic/{posts.topicSlug}#{posts.pid}" id="tid-{posts.tid}"> + + <ul id="topics-container" data-search-query="{search_query}"> + <!-- BEGIN posts --> <li class="category-item"> - <div> - <div class="col-md-12 img-thumbnail"> - <div class="search-result-post"> - <img src="{posts.picture}" /> - <strong>{posts.username}</strong>: <span class="search-result-text">{posts.content}</span> - </div> + <a href="../../topic/{posts.topicSlug}#{posts.pid}" id="tid-{posts.tid}"> + <div> + <div class="col-md-12 img-thumbnail"> + <div class="search-result-post"> + <img src="{posts.picture}" /> + <strong>{posts.username}</strong>: <span class="search-result-text">{posts.content}</span> + </div> + </div> </div> - </div> + </a> </li> - </a> - <!-- END posts --> + <!-- END posts --> </ul> </div> </div> diff --git a/public/templates/topic.tpl b/public/templates/topic.tpl index 7802c41524..a09ee029e5 100644 --- a/public/templates/topic.tpl +++ b/public/templates/topic.tpl @@ -109,7 +109,7 @@ <div class="post-info"> <span class="pull-left"> - [[topic:reputation]]: <i class='fa fa-star'></i> <span class='formatted-number'>{posts.user_rep}</span> | [[topic:posts]]: <i class='fa fa-pencil'></i> <span class='formatted-number'>{posts.user_postcount}</span> + [[topic:reputation]]: <i class='fa fa-star'></i> <span class='formatted-number post_rep_{posts.uid}'>{posts.user_rep}</span> | [[topic:posts]]: <i class='fa fa-pencil'></i> <span class='formatted-number user_postcount_{posts.uid}'>{posts.user_postcount}</span> {posts.additional_profile_info} </span> <span class="pull-right"> diff --git a/src/categoryTools.js b/src/categoryTools.js index ccbce0f4fd..e1f79e8c07 100644 --- a/src/categoryTools.js +++ b/src/categoryTools.js @@ -65,4 +65,56 @@ CategoryTools.privileges = function(cid, uid, callback) { }); }; -module.exports = CategoryTools; \ No newline at end of file +CategoryTools.groupPrivileges = function(cid, gid, callback) { + async.parallel({ + "+gr": function(next) { + var key = 'cid:' + cid + ':privileges:+gr'; + Groups.exists(key, function(err, exists) { + if (exists) { + async.parallel({ + isMember: function(next) { + Groups.isMemberByGroupName(gid, key, next); + }, + isEmpty: function(next) { + Groups.isEmptyByGroupName(key, next); + } + }, next); + } else { + next(null, { + isMember: false, + isEmpty: true + }); + } + }); + }, + "+gw": function(next) { + var key = 'cid:' + cid + ':privileges:+gw'; + Groups.exists(key, function(err, exists) { + if (exists) { + async.parallel({ + isMember: function(next) { + Groups.isMemberByGroupName(gid, key, next); + }, + isEmpty: function(next) { + Groups.isEmptyByGroupName(key, next); + } + }, next); + } else { + next(null, { + isMember: false, + isEmpty: true + }); + } + }); + } + }, function(err, privileges) { + callback(err, !privileges ? null : { + "+gr": privileges['+gr'].isMember, + "+gw": privileges['+gw'].isMember, + read: (privileges['+gr'].isMember || privileges['+gr'].isEmpty), + write: (privileges['+gw'].isMember || privileges['+gw'].isEmpty), + }); + }); +}; + +module.exports = CategoryTools; diff --git a/src/groups.js b/src/groups.js index 3d56520257..dc235fd26b 100644 --- a/src/groups.js +++ b/src/groups.js @@ -176,7 +176,6 @@ Groups.update = function(gid, values, callback) { db.exists('gid:' + gid, function (err, exists) { - console.log('exists?', gid, exists, values); if (!err && exists) { db.setObject('gid:' + gid, values, callback); } else { @@ -199,7 +198,6 @@ Groups.getGidFromName(groupName, function(err, gid) { if (err || !gid) { Groups.create(groupName, '', function(err, groupObj) { - console.log('creating group, calling hide', groupObj.gid); async.parallel([ function(next) { Groups.hide(groupObj.gid, next); @@ -263,4 +261,40 @@ }); }; + Groups.getCategoryAccess = function(cid, uid, callback){ + var access = false; + // check user group read access level + async.series([function(callback){ + // get groups with read permission + db.getObjectField('group:gid', 'cid:' + cid + ':privileges:+gr', function(err, gid){ + // get the user groups that belong to this read group + db.getSetMembers('gid:' + gid + ':members', function (err, gids) { + // check if user belong to any of these user groups + var groups_check = new Array(); + gids.forEach(function(cgid){ + groups_check.push(function(callback){ + Groups.isMember(uid, cgid, function(err, isMember){ + if (isMember){ + access = true; + } + callback(null, gids); + }) + }); + }); + // do a series check. We want to make sure we check all the groups before determining if the user + // has access or not. + async.series(groups_check, function(err, results){ + callback(null, results); + }); + }); + }); + + }], + function(err, results){ + // if the read group is empty we will asume that read access has been granted to ALL + if (results[0].length == 0){ access = true; } + callback(false, access); + }); + }; + }(module.exports)); diff --git a/src/posts.js b/src/posts.js index fd250d5b38..74c9e2fb0f 100644 --- a/src/posts.js +++ b/src/posts.js @@ -14,7 +14,8 @@ var db = require('./database'), async = require('async'), nconf = require('nconf'), validator = require('validator'), - winston = require('winston'); + winston = require('winston'), + gravatar = require('gravatar'); (function(Posts) { var customUserInfo = {}; @@ -202,12 +203,16 @@ var db = require('./database'), } postTools.parseSignature(userData.signature, function(err, signature) { + if(err) { + return callback(err); + } + post.username = userData.username || 'anonymous'; post.userslug = userData.userslug || ''; post.user_rep = userData.reputation || 0; post.user_postcount = userData.postcount || 0; post.user_banned = parseInt(userData.banned, 10) === 1; - post.picture = userData.picture || require('gravatar').url('', {}, https = nconf.get('https')); + post.picture = userData.picture || gravatar.url('', {}, https = nconf.get('https')); post.signature = signature; for (var info in customUserInfo) { @@ -217,11 +222,16 @@ var db = require('./database'), } plugins.fireHook('filter:posts.custom_profile_info', {profile: "", uid: post.uid, pid: post.pid}, function(err, profile_info) { + if(err) { + return callback(err); + } post.additional_profile_info = profile_info.profile; if (post.editor !== '') { user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) { - if (err) return callback(); + if (err) { + return callback(err); + } post.editorname = editorData.username; post.editorslug = editorData.userslug; @@ -439,8 +449,9 @@ var db = require('./database'), Posts.uploadPostImage = function(image, callback) { - if(!image) + if(!image) { return callback('invalid image', null); + } require('./imgur').upload(meta.config.imgurClientID, image.data, 'base64', function(err, data) { if(err) { @@ -455,22 +466,29 @@ var db = require('./database'), } Posts.getPostsByUid = function(uid, start, end, callback) { - user.getPostIds(uid, start, end, function(pids) { + user.getPostIds(uid, start, end, function(err, pids) { + if(err) { + return callback(err); + } if (pids && pids.length) { plugins.fireHook('filter:post.getTopic', pids, function(err, posts) { + if(err) { + return callback(err); + } - if (!err & 0 < posts.length) { + if (posts && posts.length) { Posts.getPostsByPids(pids, function(err, posts) { plugins.fireHook('action:post.gotTopic', posts); - callback(posts); + callback(null, posts); }); } else { - callback(posts); + callback(null, []); } }); - } else - callback([]); + } else { + callback(null, []); + } }); } diff --git a/src/routes/admin.js b/src/routes/admin.js index cd3994f144..3bb8783340 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -244,7 +244,7 @@ var nconf = require('nconf'), var custom_routes = { 'routes': [], - 'api_methods': [] + 'api': [] }; plugins.ready(function() { @@ -264,6 +264,19 @@ var nconf = require('nconf'), }(route)); } } + + var apiRoutes = custom_routes.api; + for (var route in apiRoutes) { + if (apiRoutes.hasOwnProperty(route)) { + (function(route) { + app[apiRoutes[route].method || 'get']('/api/admin' + apiRoutes[route].route, function(req, res) { + apiRoutes[route].callback(req, res, function(data) { + res.json(data); + }); + }); + }(route)); + } + } }); }); diff --git a/src/routes/api.js b/src/routes/api.js index ca0955ccbe..cb28e0bffb 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -4,6 +4,7 @@ var path = require('path'), db = require('../database'), user = require('../user'), + groups = require('../groups'), auth = require('./authentication'), topics = require('../topics'), posts = require('../posts'), @@ -39,33 +40,26 @@ var path = require('path'), res.json(200, config); }); - app.get('/home', function (req, res, next) { + app.get('/home', function (req, res) { var uid = (req.user) ? req.user.uid : 0; categories.getAllCategories(uid, function (err, data) { data.categories = data.categories.filter(function (category) { return (!category.disabled || parseInt(category.disabled, 10) === 0); }); - function getRecentReplies(category, callback) { + function iterator(category, callback) { categories.getRecentReplies(category.cid, 2, function (err, posts) { - if(err) { - return callback(err); - } category.posts = posts; category.post_count = posts.length > 2 ? 2 : posts.length; callback(null); }); } - async.each(data.categories, getRecentReplies, function (err) { - if(err) { - return next(err); - } - + async.each(data.categories, iterator, function (err) { data.motd_class = (parseInt(meta.config.show_motd, 10) === 1 || meta.config.show_motd === undefined) ? '' : ' none'; data.motd_class += (meta.config.motd && meta.config.motd.length > 0 ? '' : ' default'); - data.motd = require('marked')(meta.config.motd || "<div class=\"pull-right btn-group\"><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-comment\"></i><span class='hidden-mobile'> Get NodeBB</span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-github\"></i><span class='hidden-mobile'> Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-twitter\"></i><span class='hidden-mobile'> @dcplabs</span></a></div>\n\n# NodeBB <span>v" + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future."); + data.motd = require('marked')(meta.config.motd || "<div class=\"pull-right btn-group\"><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-comment\"></i><span class='hidden-mobile'> Get NodeBB</span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-github\"></i><span class='hidden-mobile'> Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-twitter\"></i><span class='hidden-mobile'> @NodeBB</span></a></div>\n\n# NodeBB <span>v" + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future."); res.json(data); }); }); @@ -128,7 +122,15 @@ var path = require('path'), if (parseInt(data.deleted, 10) === 1 && parseInt(data.expose_tools, 10) === 0) { return res.json(404, {}); } - res.json(data); + // get the category this post belongs to and check category access + var cid = data.category_slug.split("/")[0]; + groups.getCategoryAccess(cid, uid, function(err, access){ + if (access){ + res.json(data); + } else { + res.send(403); + } + }) } else next(); }); }); @@ -139,13 +141,20 @@ var path = require('path'), // Category Whitelisting categoryTools.privileges(req.params.id, uid, function(err, privileges) { if (!err && privileges.read) { - categories.getCategoryById(req.params.id, uid, function (err, data) { - if (!err && data && parseInt(data.disabled, 10) === 0) { - res.json(data); + groups.getCategoryAccess(req.params.id, uid, function(err, access){ + if (access){ + categories.getCategoryById(req.params.id, uid, function (err, data) { + if (!err && data && parseInt(data.disabled, 10) === 0) { + res.json(data); + } else { + next(); + } + }, req.params.id, uid); } else { - next(); + res.send(403); } - }, req.params.id, uid); + + }); } else { res.send(403); } @@ -244,10 +253,6 @@ var path = require('path'), return callback(err, null); } - if(pids.length > 50) { - pids = pids.splice(0, 50); - } - posts.getPostSummaryByPids(pids, false, function (err, posts) { if (err){ return callback(err, null); @@ -263,10 +268,6 @@ var path = require('path'), return callback(err, null); } - if(tids.length > 50) { - tids = tids.splice(0, 50); - } - topics.getTopicsByTids(tids, 0, function (topics) { callback(null, topics); }, 0); @@ -285,7 +286,9 @@ var path = require('path'), show_results: '', search_query: req.params.term, posts: results[0], - topics: results[1] + topics: results[1], + post_matches : results[0].length, + topic_matches : results[1].length }); }); } else { @@ -313,7 +316,7 @@ var path = require('path'), app.get('/500', function(req, res) { res.json({errorMessage: 'testing'}); - }) + }); }); } -}(exports)); \ No newline at end of file +}(exports)); diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 743ad9f9b0..5b4291d45d 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -72,7 +72,7 @@ login_strategies.push({ name: 'google', url: '/auth/google', - callbackURL: nconf.get('url') + '/auth/google/callback', + callbackURL: '/auth/google/callback', icon: 'google-plus', scope: 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email' }); @@ -95,7 +95,7 @@ login_strategies.push({ name: 'facebook', url: '/auth/facebook', - callbackURL: nconf.get('url') + '/auth/facebook/callback', + callbackURL: '/auth/facebook/callback', icon: 'facebook', scope: 'email' }); diff --git a/src/routes/user.js b/src/routes/user.js index a978e50eee..d7b88ff03e 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -181,7 +181,7 @@ var fs = require('fs'), user.setUserField(uid, 'picture', imageUrl); if (convertToPNG) { - im.convert([uploadPath, 'png:-'], + im.convert([uploadPath, 'png:-'], function(err, stdout){ if (err) { winston.err(err); @@ -191,10 +191,10 @@ var fs = require('fs'), return; } - fs.writeFileSync(uploadPath, stdout, 'binary'); + fs.writeFileSync(uploadPath, stdout, 'binary'); }); } - + res.json({ path: imageUrl @@ -393,18 +393,24 @@ var fs = require('fs'), }); }); - app.get('/api/user/:userslug', function (req, res) { + app.get('/api/user/:userslug', function (req, res, next) { var callerUID = req.user ? req.user.uid : '0'; getUserDataByUserSlug(req.params.userslug, callerUID, function (userData) { if (userData) { user.isFollowing(callerUID, userData.theirid, function (isFollowing) { - posts.getPostsByUid(userData.theirid, 0, 9, function (posts) { + posts.getPostsByUid(userData.theirid, 0, 9, function (err, posts) { + + if(err) { + return next(err); + } userData.posts = posts.filter(function (p) { return p && parseInt(p.deleted, 10) !== 1; }); + userData.isFollowing = isFollowing; + if (!userData.profileviews) { userData.profileviews = 1; } diff --git a/src/user.js b/src/user.js index bfd8f47826..fd6a6eea31 100644 --- a/src/user.js +++ b/src/user.js @@ -444,21 +444,18 @@ var bcrypt = require('bcrypt'), User.getPostIds = function(uid, start, stop, callback) { db.getListRange('uid:' + uid + ':posts', start, stop, function(err, pids) { - if (!err) { - if (pids && pids.length) { - callback(pids); - } else { - callback([]); - } + if(err) { + return callback(err); + } + + if (pids && pids.length) { + callback(null, pids); } else { - console.log(err); - callback([]); + callback(null, []); } }); }; - - User.follow = function(uid, followid, callback) { db.setAdd('following:' + uid, followid, function(err, data) { if (!err) { diff --git a/src/websockets.js b/src/websockets.js index b7ccb81ee2..2000b34617 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -591,9 +591,9 @@ websockets.init = function(io) { threadTools.move(data.tid, data.cid, socket); }); - socket.on('api:categories.get', function() { + socket.on('api:categories.get', function(callback) { categories.getAllCategories(0, function(err, categories) { - socket.emit('api:categories.get', categories); + callback(categories); }); }); @@ -714,10 +714,10 @@ websockets.init = function(io) { return; } - var finalMessage = username + ' : ' + msg, - notifText = 'New message from <strong>' + username + '</strong>', - username = usersData[0].username, - toUsername = usersData[1].username; + var username = usersData[0].username, + toUsername = usersData[1].username, + finalMessage = username + ' : ' + msg, + notifText = 'New message from <strong>' + username + '</strong>'; if (!isUserOnline(touid)) { notifications.create(notifText, 'javascript:app.openChat('' + username + '', ' + uid + ');', 'notification_' + uid + '_' + touid, function(nid) { @@ -1084,6 +1084,37 @@ websockets.init = function(io) { }); }); + socket.on('api:admin.categories.setGroupPrivilege', function(cid, gid, privilege, set, callback) { + var cb = function(err) { + CategoryTools.groupPrivileges(cid, gid, callback); + }; + + if (set) { + groups.joinByGroupName('cid:' + cid + ':privileges:' + privilege, gid, cb); + } else { + groups.leaveByGroupName('cid:' + cid + ':privileges:' + privilege, gid, cb); + } + }); + + socket.on('api:admin.categories.groupsearch', function(cid, callback) { + groups.list({expand:false}, function(err, data){ + async.map(data, function(groupObj, next) { + CategoryTools.groupPrivileges(cid, groupObj.gid, function(err, privileges) { + if (!err) { + groupObj.privileges = privileges; + } else { + winston.error('[socket api:admin.categories.groupsearch] Could not retrieve permissions'); + } + + next(null, groupObj); + }); + }, function(err, data) { + if (!callback) socket.emit('api:admin.categories.groupsearch', data); + else callback(null, data); + }); + }); + }); + socket.on('api:admin.themes.getInstalled', function(callback) { meta.themes.get(function(err, themeArr) { callback(themeArr);