Merge pull request #4402 from HabitRPG/add-flag-to-chat

Add flag to chat
This commit is contained in:
Matteo Pagliazzi
2014-12-23 18:36:23 +01:00
9 changed files with 177 additions and 9 deletions
+1
View File
@@ -21,6 +21,7 @@
"NEW_RELIC_APPLICATION_ID":"NEW_RELIC_APPLICATION_ID",
"NEW_RELIC_API_KEY":"NEW_RELIC_API_KEY",
"GA_ID": "GA_ID",
"FLAG_REPORT_EMAIL": "email@mod.com",
"EMAIL_SERVER": {
"url": "http://example.com",
"authUser": "user",
+3
View File
@@ -135,6 +135,9 @@ a
a span.glyphicon
color: #333 // Takes base color from bootstrap
&.text-danger
color: #a94442 // Allows glyphicon to use text-danger class
a.label
color: #fff
+33 -3
View File
@@ -108,8 +108,8 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
}
])
.controller("MemberModalCtrl", ['$scope', '$rootScope', 'Members', 'Shared', '$http', 'Notification',
function($scope, $rootScope, Members, Shared, $http, Notification) {
.controller("MemberModalCtrl", ['$scope', '$rootScope', 'Members', 'Shared', '$http', 'Notification', 'Groups',
function($scope, $rootScope, Members, Shared, $http, Notification, Groups) {
$scope.timestamp = function(timestamp){
return moment(timestamp).format('MM/DD/YYYY');
}
@@ -139,6 +139,20 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
$scope.$close();
})
}
$scope.reportAbuse = function(reporter, message, groupId) {
message.flags[reporter._id] = true;
Groups.Group.flagChatMessage({gid: groupId, messageId: message.id}, undefined, function(data){
Notification.text(window.env.t('abuseReported'));
$scope.$close();
});
}
$scope.clearFlagCount = function(message, groupId) {
Groups.Group.clearFlagCount({gid: groupId, messageId: message.id}, undefined, function(data){
message.flagCount = 0;
Notification.text("Flags cleared");
$scope.$close();
});
}
}
])
@@ -197,7 +211,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
});
}])
.controller('ChatCtrl', ['$scope', 'Groups', 'User', '$http', 'ApiUrlService', 'Notification', function($scope, Groups, User, $http, ApiUrlService, Notification){
.controller('ChatCtrl', ['$scope', 'Groups', 'User', '$http', 'ApiUrlService', 'Notification', 'Members', '$rootScope', function($scope, Groups, User, $http, ApiUrlService, Notification, Members, $rootScope){
$scope.message = {content:''};
$scope._sending = false;
@@ -262,6 +276,22 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
$http.post(ApiUrlService.get() + '/api/v2/groups/' + group._id + '/chat/' + message.id + '/like');
}
$scope.flagChatMessage = function(groupId,message) {
if(!message.flags) message.flags = {};
if(message.flags[User.user._id])
Notification.text(window.env.t('abuseAlreadyReported'));
else {
$scope.abuseObject = message;
$scope.groupId = groupId;
Members.selectMember(message.uuid, function(){
$rootScope.openModal('abuse-flag',{
controller:'MemberModalCtrl',
scope: $scope
});
});
}
}
$scope.sync = function(group){
group.$get();
}
+2
View File
@@ -13,6 +13,8 @@ angular.module('groupServices', ['ngResource']).
//query: {method: "GET", isArray:false},
postChat: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/chat'},
deleteChatMessage: {method: "DELETE", url: ApiUrlService.get() + '/api/v2/groups/:gid/chat/:messageId'},
flagChatMessage: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/chat/:messageId/flag'},
clearFlagCount: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/chat/:messageId/clearflags'},
join: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/join'},
leave: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/leave'},
invite: {method: "POST", url: ApiUrlService.get() + '/api/v2/groups/:gid/invite'},
+78
View File
@@ -7,10 +7,12 @@ function clone(a) {
var _ = require('lodash');
var nconf = require('nconf');
var async = require('async');
var utils = require('./../utils');
var shared = require('habitrpg-shared');
var User = require('./../models/user').model;
var Group = require('./../models/group').model;
var Challenge = require('./../models/challenge').model;
var isProd = nconf.get('NODE_ENV') === 'production';
var api = module.exports;
/*
@@ -256,6 +258,82 @@ api.deleteChatMessage = function(req, res, next){
});
}
api.flagChatMessage = function(req, res, next){
var user = res.locals.user
var group = res.locals.group;
var message = _.find(group.chat, {id: req.params.mid});
if(!message) return res.json(404, {err: "Message not found!"});
if(message.uuid == user._id) return res.json(401, {err: "Can't report your own message."});
User.findOne({_id: message.uuid}, {auth: 1}, function(err, author){
if(err) return next(err);
// Log user ids that have flagged the message
if(!message.flags) message.flags = {};
if(message.flags[user._id] && !user.contributor.admin) return res.json(401, {err: "You have already reported this message"});
message.flags[user._id] = true;
// Log total number of flags (publicly viewable)
if(!message.flagCount) message.flagCount = 0;
if(user.contributor.admin){
// Arbitraty amount, higher than 2
message.flagCount = 5;
} else {
message.flagCount++
}
group.markModified('chat');
group.save(function(err,_saved){
if(err) return next(err);
if (isProd){
utils.txnEmail({email: nconf.get('FLAG_REPORT_EMAIL')}, 'flag-report-to-mods', [
{name: "MESSAGE_TIME", content: message.timestamp},
{name: "MESSAGE_TEXT", content: message.text},
{name: "REPORTER_USERNAME", content: user.profile.name},
{name: "REPORTER_UUID", content: user._id},
{name: "REPORTER_EMAIL", content: user.auth.local ? user.auth.local.email : ((user.auth.facebook && user.auth.facebook.emails && user.auth.facebook.emails[0]) ? user.auth.facebook.emails[0].value : null)},
{name: "REPORTER_MODAL_URL", content: "https://habitrpg.com/static/front/#?memberId=" + user._id},
{name: "AUTHOR_USERNAME", content: message.user},
{name: "AUTHOR_UUID", content: message.uuid},
{name: "AUTHOR_EMAIL", content: author.auth.local ? author.auth.local.email : ((author.auth.facebook && author.auth.facebook.emails && author.auth.facebook.emails[0]) ? author.auth.facebook.emails[0].value : null)},
{name: "AUTHOR_MODAL_URL", content: "https://habitrpg.com/static/front/#?memberId=" + message.uuid},
{name: "GROUP_NAME", content: group.name},
{name: "GROUP_TYPE", content: group.type},
{name: "GROUP_ID", content: group._id},
{name: "GROUP_URL", content: group._id == 'habitrpg' ? (nconf.get('BASE_URL') + '/#/options/groups/tavern') : (group.type === 'guild' ? (nconf.get('BASE_URL')+ '/#/options/groups/guilds/' + group._id) : 'party')},
]);
}
return res.send(204);
});
});
}
api.clearFlagCount = function(req, res, next){
var user = res.locals.user
var group = res.locals.group;
var message = _.find(group.chat, {id: req.params.mid});
if(!message) return res.json(404, {err: "Message not found!"});
if(user.contributor.admin){
message.flagCount = 0;
group.markModified('chat');
group.save(function(err,_saved){
if(err) return next(err);
return res.send(204);
});
}else{
return res.json(401, {err: "Only an admin can clear the flag count!"})
}
}
api.seenMessage = function(req,res,next){
// Skip the auth step, we want this to be fast. If !found with uuid/token, then it just doesn't save
// Check for req.params.gid to exist
+16 -2
View File
@@ -101,7 +101,9 @@ var chatDefaults = module.exports.chatDefaults = function(msg,user){
id: shared.uuid(),
text: msg,
timestamp: +new Date,
likes: {}
likes: {},
flags: {},
flagCount: 0
};
if (user) {
_.defaults(message, {
@@ -319,6 +321,18 @@ GroupSchema.statics.bossQuest = function(user, progress, cb) {
})
}
GroupSchema.methods.toJSON = function() {
var doc = this.toObject();
if(doc.chat){
doc.chat.forEach(function(msg){
msg.flags = {};
});
}
return doc;
};
module.exports.schema = GroupSchema;
var Group = module.exports.model = mongoose.model("Group", GroupSchema);
@@ -333,4 +347,4 @@ Group.count({_id:'habitrpg'},function(err,ct){
type: 'guild',
privacy:'public'
}).save();
})
})
+22
View File
@@ -577,6 +577,28 @@ module.exports = (swagger, v2) ->
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup]
action: groups.likeChatMessage
"/groups/{gid}/chat/{mid}/flag":
spec:
method: 'POST'
description: "Flag a chat message"
parameters: [
path 'gid','Group id','string'
path 'mid','Message id','string'
]
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup]
action: groups.flagChatMessage
"/groups/{gid}/chat/{mid}/clearflags":
spec:
method: 'POST'
description: "Clear flag count from message and unhide it"
parameters: [
path 'gid','Group id','string'
path 'mid','Message id','string'
]
middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup]
action: groups.clearFlagCount
# ---------------------------------
# Members
# ---------------------------------
+8 -3
View File
@@ -1,8 +1,10 @@
mixin chatMessages(inbox)
ul.list-unstyled.tavern-chat
- var ngRepeat = inbox ? 'message in user.inbox.messages | toArray:true | orderBy:"sort":true' : 'message in group.chat track by message.id'
li.chat-message(ng-repeat=ngRepeat, ng-class=':: {highlight: isUserMentioned(user,message) || message.uuid=="system", "own-message": user._id == message.uuid}', style='{{::message.sent ? "opacity:0.5" : ""}}')
.scrollable-message
li.chat-message(ng-repeat=ngRepeat, ng-class=':: {highlight: isUserMentioned(user,message) || message.uuid=="system", "own-message": user._id == message.uuid}', ng-if="!message.flagCount || message.flagCount < 2 || user.contributor.admin")
span.pull-right.text-danger(ng-if="user.contributor.admin && message.flagCount > 0")
| {{message.flagCount > 1 ? "Message Hidden" : "1 flag"}}
.scrollable-message(ng-class='{"transparent": message.sent || message.flags[user._id] || (user.contributor.admin && message.flagCount > 1)}')
span(ng-if='::message.user')
a.label.label-default.chat-message.hidden-label
span.glyphicon.glyphicon-arrow-right(ng-if='::message.sent')
@@ -23,9 +25,12 @@ mixin chatMessages(inbox)
if inbox
a(ng-click="quickReply(message.uuid)")
span.glyphicon.glyphicon-share-alt(tooltip=env.t('pm-reply'))
| &nbsp; &nbsp; &nbsp; &nbsp;
| &nbsp; &nbsp;
a(ng-click='#{inbox? "user.ops.deletePM({params:{id:message.$key}})" : "deleteChatMessage(group, message)"}', ng-if='#{inbox ? "true" : ":: user.contributor.admin || message.uuid == user.id"}')
span.glyphicon.glyphicon-trash(tooltip=env.t('delete'))
| &nbsp; &nbsp;
a(ng-click="flagChatMessage(group._id, message)", ng-if=':: user.contributor.admin || (!message.sent && user.flags.communityGuidelinesAccepted && message.uuid != user.id && message.uuid != "system")')
span.glyphicon.glyphicon-flag(tooltip="{{message.flags[user._id] ? env.t('abuseAlreadyReported') : env.t('abuseFlag')}}" ng-class='message.flags[user._id] ? "text-danger" : ""')
span.float-label(ng-class='::contribText(message.contributor, message.backer).length > 30 ? "long-title" : ""')
a.label.label-default.chat-message(ng-if=':: message.user', ng-class='::userLevelStyleFromLevel(message.contributor.level, message.backer.npc, style)', ng-click='clickMember(message.uuid, true)')
span.glyphicon.glyphicon-arrow-right(ng-if='::message.sent')
+14 -1
View File
@@ -88,4 +88,17 @@ script(type='text/ng-template', id='modals/send-gift.html')
button.btn.btn-primary(ng-show=fromBal, ng-click='sendGift(profile._id, gift)')=env.t("send")
a.btn.btn-primary(ng-hide=fromBal, ng-click='Payments.showStripe({gift:gift, uuid:profile._id})')=env.t('card')
a.btn.btn-warning(ng-hide=fromBal, href='/paypal/checkout?_id={{::user._id}}&apiToken={{::user.apiToken}}&gift={{Payments.encodeGift(profile._id, gift)}}') PayPal
button.btn.btn-default(ng-click='$close()')=env.t('cancel')
button.btn.btn-default(ng-click='$close()')=env.t('cancel')
script(type='text/ng-template', id='modals/abuse-flag.html')
.modal-header
h4!=env.t('abuseFlagModalHeading', {name: "<span class='text-danger'>{{profile.profile.name}}</span>"})
.modal-body
blockquote
markdown(ng-model="abuseObject.text")
p!=env.t('abuseFlagModalBody', {firstLinkStart: "<a href='/static/community-guidelines' target='_blank'>", secondLinkStart: "<a href='/static/terms' target='_blank'>", linkEnd: "</a>"})
.modal-footer
button.pull-left.btn.btn-danger(ng-click='clearFlagCount(abuseObject, groupId)', ng-if='user.contributor.admin && abuseObject.flagCount >= 2')
| Reset Flag Count
button.btn.btn-primary(ng-click='$close()')=env.t('cancel')
button.btn.btn-default(ng-click='reportAbuse(user, abuseObject, groupId)')=env.t("abuseFlagModalButton")