Basic Functionality
This commit is contained in:
commit
9b20e633c0
|
@ -0,0 +1,102 @@
|
|||
{
|
||||
"env": {
|
||||
"jasmine": true,
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"browser": true,
|
||||
"builtin": true
|
||||
},
|
||||
ecmaVersion: 7,
|
||||
"globals":
|
||||
{"Ember":true,
|
||||
"jQuery":true,
|
||||
"$":true,
|
||||
"RSVP":true,
|
||||
"Discourse":true,
|
||||
"Em":true,
|
||||
"PreloadStore":true,
|
||||
"Handlebars":true,
|
||||
"I18n":true,
|
||||
"bootbox":true,
|
||||
"module":true,
|
||||
"moduleFor":true,
|
||||
"moduleForComponent":true,
|
||||
"Pretender":true,
|
||||
"sandbox":true,
|
||||
"controllerFor":true,
|
||||
"test":true,
|
||||
"ok":true,
|
||||
"not":true,
|
||||
"expect":true,
|
||||
"equal":true,
|
||||
"visit":true,
|
||||
"andThen":true,
|
||||
"click":true,
|
||||
"currentPath":true,
|
||||
"currentRouteName":true,
|
||||
"currentURL":true,
|
||||
"fillIn":true,
|
||||
"keyEvent":true,
|
||||
"triggerEvent":true,
|
||||
"count":true,
|
||||
"exists":true,
|
||||
"visible":true,
|
||||
"invisible":true,
|
||||
"asyncRender":true,
|
||||
"selectDropdown":true,
|
||||
"asyncTestDiscourse":true,
|
||||
"fixture":true,
|
||||
"find":true,
|
||||
"sinon":true,
|
||||
"moment":true,
|
||||
"start":true,
|
||||
"_":true,
|
||||
"alert":true,
|
||||
"containsInstance":true,
|
||||
"deepEqual":true,
|
||||
"notEqual":true,
|
||||
"define":true,
|
||||
"require":true,
|
||||
"requirejs":true,
|
||||
"hasModule":true,
|
||||
"Blob":true,
|
||||
"File":true},
|
||||
"rules": {
|
||||
"block-scoped-var": 2,
|
||||
"dot-notation": 0,
|
||||
"eqeqeq": [
|
||||
2,
|
||||
"allow-null"
|
||||
],
|
||||
"guard-for-in": 2,
|
||||
"no-bitwise": 2,
|
||||
"no-caller": 2,
|
||||
"no-cond-assign": 0,
|
||||
"no-debugger": 2,
|
||||
"no-empty": 0,
|
||||
"no-eval": 2,
|
||||
"no-extend-native": 2,
|
||||
"no-extra-parens": 0,
|
||||
"no-irregular-whitespace": 2,
|
||||
"no-iterator": 2,
|
||||
"no-loop-func": 2,
|
||||
"no-multi-str": 2,
|
||||
"no-new": 2,
|
||||
"no-plusplus": 0,
|
||||
"no-proto": 2,
|
||||
"no-script-url": 2,
|
||||
"no-sequences": 2,
|
||||
"no-shadow": 2,
|
||||
"no-undef": 2,
|
||||
"no-unused-vars": 2,
|
||||
"no-with": 2,
|
||||
"semi": 2,
|
||||
"strict": 0,
|
||||
"valid-typeof": 2,
|
||||
"wrap-iife": [
|
||||
2,
|
||||
"inside"
|
||||
]
|
||||
},
|
||||
"parser": "babel-eslint"
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { default as computed, on } from 'ember-addons/ember-computed-decorators';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
newNote: null,
|
||||
saving: false,
|
||||
|
||||
@on('init')
|
||||
reset() {
|
||||
this.setProperties({ newNote: null, saving: false });
|
||||
},
|
||||
|
||||
@computed('newNote', 'saving')
|
||||
attachDisabled(newNote, saving) {
|
||||
return saving || !newNote || (newNote.length === 0);
|
||||
},
|
||||
|
||||
actions: {
|
||||
attachNote() {
|
||||
const note = this.store.createRecord('staff-note');
|
||||
this.set('saving', true);
|
||||
note.save({ raw: this.get('newNote'), user_id: this.get('userId') }).then(() => {
|
||||
this.set('newNote', '');
|
||||
this.get('model').pushObject(note);
|
||||
}).catch(popupAjaxError).finally(() => this.set('saving', false));
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
import { withPluginApi } from 'discourse/lib/plugin-api';
|
||||
import showModal from 'discourse/lib/show-modal';
|
||||
|
||||
export default {
|
||||
name: 'enable-staff-notes',
|
||||
initialize(container) {
|
||||
const siteSettings = container.lookup('site-settings:main');
|
||||
if (!siteSettings.staff_notes_enabled) { return; }
|
||||
|
||||
withPluginApi('0.2', api => {
|
||||
api.decorateWidget('poster-name:after', dec => dec.attach('staff-notes-icon'));
|
||||
|
||||
api.createWidget('staff-notes-icon', {
|
||||
tagName: 'span.staff-notes-icon',
|
||||
|
||||
html() {
|
||||
return this.attach('emoji', { name: 'pencil' });
|
||||
},
|
||||
|
||||
click() {
|
||||
return this.store.find('staff-note', { user_id: this.attrs.user_id }).then(model => {
|
||||
const controller = showModal('staff-notes', { model, title: 'staff_notes.title' });
|
||||
controller.reset();
|
||||
controller.set('userId', this.attrs.user_id);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
<div class="modal-body staff-notes-modal">
|
||||
|
||||
{{#each model as |n|}}
|
||||
<div class='staff-note'>
|
||||
<div class='posted-by'>
|
||||
{{avatar n.created_by imageSize="tiny"}}
|
||||
</div>
|
||||
<div class='cooked'>{{cook-text n.raw}}</div>
|
||||
<div class='clearfix'></div>
|
||||
</div>
|
||||
{{/each}}
|
||||
|
||||
{{textarea value=newNote}}
|
||||
{{d-button action="attachNote" label="staff_notes.attach" class="btn-primary" disabled=attachDisabled}}
|
||||
|
||||
</div>
|
|
@ -0,0 +1,23 @@
|
|||
.staff-notes-modal {
|
||||
height: 300px;
|
||||
|
||||
.posted-by {
|
||||
width: 30px;
|
||||
float: left;
|
||||
}
|
||||
.cooked {
|
||||
float: left;
|
||||
|
||||
p {
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
}
|
||||
|
||||
.staff-note {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.staff-notes-icon {
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
en:
|
||||
js:
|
||||
staff_notes:
|
||||
title: "Staff Notes"
|
||||
attach: "Attach Note"
|
|
@ -0,0 +1,3 @@
|
|||
en:
|
||||
site_settings:
|
||||
staff_notes_enabled: "Allow staff users to attach notes to users"
|
|
@ -0,0 +1,4 @@
|
|||
plugins:
|
||||
staff_notes_enabled:
|
||||
default: false
|
||||
client: true
|
|
@ -0,0 +1,99 @@
|
|||
# name: staff-notes
|
||||
# about: Gives the ability for staff members to attach notes to users
|
||||
# version: 0.0.1
|
||||
# authors: Robin Ward
|
||||
|
||||
enabled_site_setting :staff_notes_enabled
|
||||
|
||||
register_asset 'stylesheets/staff_notes.scss'
|
||||
|
||||
after_initialize do
|
||||
|
||||
require_dependency 'user'
|
||||
|
||||
module ::DiscourseStaffNotes
|
||||
class Engine < ::Rails::Engine
|
||||
engine_name "discourse_staff_notes"
|
||||
isolate_namespace DiscourseStaffNotes
|
||||
end
|
||||
|
||||
def self.key_for(user_id)
|
||||
"notes:#{user_id}"
|
||||
end
|
||||
|
||||
def self.notes_for(user_id)
|
||||
PluginStore.get('staff_notes', key_for(user_id)) || []
|
||||
end
|
||||
|
||||
def self.add_note(user_id, raw, created_by)
|
||||
notes = notes_for(user_id)
|
||||
record = { id: SecureRandom.hex(16), raw: raw, created_by: created_by, created_at: Time.now }
|
||||
notes << record
|
||||
::PluginStore.set("staff_notes", key_for(user_id), notes)
|
||||
|
||||
record
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
require_dependency 'application_serializer'
|
||||
class ::StaffNoteSerializer < ApplicationSerializer
|
||||
attributes :id, :raw, :created_by, :created_at
|
||||
|
||||
def id
|
||||
object[:id]
|
||||
end
|
||||
|
||||
def raw
|
||||
object[:raw]
|
||||
end
|
||||
|
||||
def created_by
|
||||
user = User.where(id: object[:created_by]).first
|
||||
return nil if user.blank?
|
||||
|
||||
BasicUserSerializer.new(user, scope: scope, root: false)
|
||||
end
|
||||
|
||||
def created_at
|
||||
object[:created_at]
|
||||
end
|
||||
end
|
||||
|
||||
require_dependency 'application_controller'
|
||||
class DiscourseStaffNotes::StaffNotesController < ::ApplicationController
|
||||
before_filter :ensure_logged_in
|
||||
before_filter :ensure_staff
|
||||
|
||||
def index
|
||||
user = User.where(id: params[:user_id]).first
|
||||
raise Discourse::NotFound if user.blank?
|
||||
|
||||
notes = ::DiscourseStaffNotes.notes_for(params[:user_id])
|
||||
render json: {
|
||||
extras: { username: user.username },
|
||||
staff_notes: serialize_data(notes, ::StaffNoteSerializer)
|
||||
}
|
||||
end
|
||||
|
||||
def create
|
||||
user_id = params[:staff_note][:user_id]
|
||||
|
||||
user = User.where(id: user_id).first
|
||||
raise Discourse::NotFound if user.blank?
|
||||
staff_note = ::DiscourseStaffNotes.add_note(user.id, params[:staff_note][:raw], current_user.id)
|
||||
|
||||
render json: serialize_data(staff_note, ::StaffNoteSerializer)
|
||||
end
|
||||
end
|
||||
|
||||
DiscourseStaffNotes::Engine.routes.draw do
|
||||
get '/' => 'staff_notes#index'
|
||||
post '/' => 'staff_notes#create'
|
||||
end
|
||||
|
||||
Discourse::Application.routes.append do
|
||||
mount ::DiscourseStaffNotes::Engine, at: "/staff_notes"
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue