diff --git a/app/assets/javascripts/admin/templates/group.hbs b/app/assets/javascripts/admin/templates/group.hbs
index 42993a1e923..3b06790e439 100644
--- a/app/assets/javascripts/admin/templates/group.hbs
+++ b/app/assets/javascripts/admin/templates/group.hbs
@@ -4,15 +4,15 @@
{{#if model.automatic}}
diff --git a/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6 b/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6
index f14d45da630..ce4113450b3 100644
--- a/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6
+++ b/app/assets/javascripts/discourse/components/group-flair-inputs.js.es6
@@ -45,6 +45,6 @@ export default Ember.Component.extend({
@computed('flairPreviewImage')
flairPreviewLabel(flairPreviewImage) {
const key = flairPreviewImage ? 'image' : 'icon';
- return I18n.t(`group.flair_preview_${key}`);
+ return I18n.t(`groups.flair_preview_${key}`);
}
});
diff --git a/app/assets/javascripts/discourse/components/group-logs-filter.js.es6 b/app/assets/javascripts/discourse/components/group-logs-filter.js.es6
new file mode 100644
index 00000000000..ba4ccc3f742
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/group-logs-filter.js.es6
@@ -0,0 +1,21 @@
+import computed from 'ember-addons/ember-computed-decorators';
+
+export default Ember.Component.extend({
+ tagName: '',
+
+ @computed('type')
+ label(type) {
+ return I18n.t(`groups.logs.${type}`);
+ },
+
+ @computed('value', 'type')
+ filterText(value, type) {
+ return type === 'action' ? I18n.t(`group_histories.actions.${value}`) : value;
+ },
+
+ actions: {
+ clearFilter(param) {
+ this.sendAction("clearFilter", param);
+ }
+ }
+});
diff --git a/app/assets/javascripts/discourse/components/group-logs-row.js.es6 b/app/assets/javascripts/discourse/components/group-logs-row.js.es6
new file mode 100644
index 00000000000..5b46af4d61d
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/group-logs-row.js.es6
@@ -0,0 +1,14 @@
+export default Ember.Component.extend({
+ tagName: '',
+ expandDetails: false,
+
+ actions: {
+ toggleDetails() {
+ this.toggleProperty('expandDetails');
+ },
+
+ filter(params) {
+ this.set(`filters.${params.key}`, params.value);
+ }
+ }
+});
diff --git a/app/assets/javascripts/discourse/controllers/group-index.js.es6 b/app/assets/javascripts/discourse/controllers/group-index.js.es6
index 57a3f4c8bd5..385ad7414e6 100644
--- a/app/assets/javascripts/discourse/controllers/group-index.js.es6
+++ b/app/assets/javascripts/discourse/controllers/group-index.js.es6
@@ -1,6 +1,6 @@
import { popupAjaxError } from 'discourse/lib/ajax-error';
import Group from 'discourse/models/group';
-import { observes } from 'ember-addons/ember-computed-decorators';
+import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
export default Ember.Controller.extend({
queryParams: ['order', 'desc'],
@@ -17,6 +17,11 @@ export default Ember.Controller.extend({
this.get('model').findMembers({ order: this.get('order'), desc: this.get('desc') });
},
+ @computed("model.public")
+ canJoinGroup(publicGroup) {
+ return !!(this.currentUser) && publicGroup;
+ },
+
actions: {
removeMember(user) {
this.get('model').removeMember(user);
@@ -29,6 +34,28 @@ export default Ember.Controller.extend({
}
},
+ joinGroup() {
+ this.set('updatingMembership', true);
+ const model = this.get('model');
+
+ model.addMembers(this.currentUser.get('username')).then(() => {
+ model.set('is_group_user', true);
+ }).catch(popupAjaxError).finally(() => {
+ this.set('updatingMembership', false);
+ });
+ },
+
+ leaveGroup() {
+ this.set('updatingMembership', true);
+ const model = this.get('model');
+
+ model.removeMember(this.currentUser).then(() => {
+ model.set('is_group_user', false);
+ }).catch(popupAjaxError).finally(() => {
+ this.set('updatingMembership', false);
+ });
+ },
+
loadMore() {
if (this.get("loading")) { return; }
if (this.get("model.members.length") >= this.get("model.user_count")) { return; }
diff --git a/app/assets/javascripts/discourse/controllers/group-logs.js.es6 b/app/assets/javascripts/discourse/controllers/group-logs.js.es6
new file mode 100644
index 00000000000..0019127c3a6
--- /dev/null
+++ b/app/assets/javascripts/discourse/controllers/group-logs.js.es6
@@ -0,0 +1,57 @@
+import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
+
+export default Ember.Controller.extend({
+ group: Ember.inject.controller(),
+ loading: false,
+ offset: 0,
+
+ init() {
+ this._super();
+ this.set('filters', Ember.Object.create());
+ },
+
+ @computed('filters.action', 'filters.acting_user', 'filters.target_user', 'filters.subject')
+ filterParams(action, acting_user, target_user, subject) {
+ return { action, acting_user, target_user, subject };
+ },
+
+ @observes('filters.action', 'filters.acting_user', 'filters.target_user', 'filters.subject')
+ _refreshModel() {
+ this.get('group.model').findLogs(0, this.get('filterParams')).then(results => {
+ this.set('offset', 0);
+
+ this.get('model').setProperties({
+ logs: results.logs,
+ all_loaded: results.all_loaded
+ });
+ });
+ },
+
+ reset() {
+ this.setProperties({
+ offset: 0,
+ filters: Ember.Object.create()
+ });
+ },
+
+ actions: {
+ loadMore() {
+ if (this.get('model.all_loaded')) return;
+
+ this.set('loading', true);
+
+ this.get('group.model').findLogs(this.get('offset') + 1, this.get('filterParams'))
+ .then(results => {
+ results.logs.forEach(result => this.get('model.logs').addObject(result));
+ this.incrementProperty('offset');
+ this.set('model.all_loaded', results.all_loaded);
+ }).finally(() => {
+ this.set('loading', false);
+ });
+ },
+
+ clearFilter(key) {
+ this.set(`filters.${key}`, '');
+ }
+ }
+});
diff --git a/app/assets/javascripts/discourse/controllers/group.js.es6 b/app/assets/javascripts/discourse/controllers/group.js.es6
index c4c4eae3267..800097d86db 100644
--- a/app/assets/javascripts/discourse/controllers/group.js.es6
+++ b/app/assets/javascripts/discourse/controllers/group.js.es6
@@ -6,9 +6,9 @@ var Tab = Em.Object.extend({
return 'group.' + name;
},
- @computed('name')
- message(name) {
- return I18n.t('groups.' + name);
+ @computed('name', 'i18nKey')
+ message(name, i18nKey) {
+ return I18n.t(`groups.${i18nKey || name}`);
}
});
@@ -20,7 +20,8 @@ export default Ember.Controller.extend({
Tab.create({ name: 'posts' }),
Tab.create({ name: 'topics' }),
Tab.create({ name: 'mentions' }),
- Tab.create({ name: 'messages', requiresMembership: true })
+ Tab.create({ name: 'messages', requiresMembership: true }),
+ Tab.create({ name: 'logs', i18nKey: 'logs.title', icon: 'shield', requiresMembership: true })
],
@computed('model.is_group_owner', 'model.automatic')
diff --git a/app/assets/javascripts/discourse/models/group-history.js.es6 b/app/assets/javascripts/discourse/models/group-history.js.es6
new file mode 100644
index 00000000000..18b644d163c
--- /dev/null
+++ b/app/assets/javascripts/discourse/models/group-history.js.es6
@@ -0,0 +1,9 @@
+import computed from 'ember-addons/ember-computed-decorators';
+import RestModel from 'discourse/models/rest';
+
+export default RestModel.extend({
+ @computed('action')
+ actionTitle(action) {
+ return I18n.t(`group_histories.actions.${action}`);
+ }
+});
diff --git a/app/assets/javascripts/discourse/models/group.js.es6 b/app/assets/javascripts/discourse/models/group.js.es6
index 42f9575e1f7..7d8a58cec66 100644
--- a/app/assets/javascripts/discourse/models/group.js.es6
+++ b/app/assets/javascripts/discourse/models/group.js.es6
@@ -1,5 +1,6 @@
import { ajax } from 'discourse/lib/ajax';
import computed from "ember-addons/ember-computed-decorators";
+import GroupHistory from 'discourse/models/group-history';
const Group = Discourse.Model.extend({
limit: 50,
@@ -114,7 +115,8 @@ const Group = Discourse.Model.extend({
flair_url: this.get('flair_url'),
flair_bg_color: this.get('flairBackgroundHexColor'),
flair_color: this.get('flairHexColor'),
- bio_raw: this.get('bio_raw')
+ bio_raw: this.get('bio_raw'),
+ public: this.get('public')
};
},
@@ -140,6 +142,15 @@ const Group = Discourse.Model.extend({
return ajax("/admin/groups/" + this.get('id'), { type: "DELETE" });
},
+ findLogs(offset, filters) {
+ return ajax(`/groups/${this.get('name')}/logs.json`, { data: { offset, filters } }).then(results => {
+ return Ember.Object.create({
+ logs: results["logs"].map(log => GroupHistory.create(log)),
+ all_loaded: results["all_loaded"]
+ });
+ });
+ },
+
findPosts(opts) {
opts = opts || {};
diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
index a1de0bfc74e..37733386f1f 100644
--- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6
+++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
@@ -56,6 +56,7 @@ export default function() {
this.route('topics');
this.route('mentions');
this.route('messages');
+ this.route('logs');
});
// User routes
diff --git a/app/assets/javascripts/discourse/routes/group-logs.js.es6 b/app/assets/javascripts/discourse/routes/group-logs.js.es6
new file mode 100644
index 00000000000..0d365fab188
--- /dev/null
+++ b/app/assets/javascripts/discourse/routes/group-logs.js.es6
@@ -0,0 +1,20 @@
+export default Ember.Route.extend({
+ titleToken() {
+ return I18n.t('groups.logs');
+ },
+
+ model() {
+ return this.modelFor('group').findLogs();
+ },
+
+ setupController(controller, model) {
+ this.controllerFor('group-logs').setProperties({ model });
+ this.controllerFor("group").set("showing", 'logs');
+ },
+
+ actions: {
+ willTransition() {
+ this.controllerFor('group-logs').reset();
+ }
+ }
+});
diff --git a/app/assets/javascripts/discourse/templates/components/group-flair-inputs.hbs b/app/assets/javascripts/discourse/templates/components/group-flair-inputs.hbs
index 1e75c9655f7..5693422c4d5 100644
--- a/app/assets/javascripts/discourse/templates/components/group-flair-inputs.hbs
+++ b/app/assets/javascripts/discourse/templates/components/group-flair-inputs.hbs
@@ -1,31 +1,31 @@
-
+
{{text-field name="flair_url"
value=model.flair_url
- placeholderKey="group.flair_url_placeholder"}}
+ placeholderKey="groups.flair_url_placeholder"}}
-
+
{{text-field name="flair_bg_color"
class="group-flair-bg-color"
value=model.flair_bg_color
- placeholderKey="group.flair_bg_color_placeholder"}}
+ placeholderKey="groups.flair_bg_color_placeholder"}}
{{#if flairPreviewIcon}}
-
+
{{text-field name="flair_color"
class="group-flair-color"
value=model.flair_color
- placeholderKey="group.flair_color_placeholder"}}
+ placeholderKey="groups.flair_color_placeholder"}}
{{/if}}
- {{i18n 'group.flair_note'}}
+ {{i18n 'groups.flair_note'}}
diff --git a/app/assets/javascripts/discourse/templates/components/group-logs-filter.hbs b/app/assets/javascripts/discourse/templates/components/group-logs-filter.hbs
new file mode 100644
index 00000000000..11c1eb7b558
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/group-logs-filter.hbs
@@ -0,0 +1,6 @@
+{{#if value}}
+ {{#d-button class="btn-small group-logs-filter" action="clearFilter" actionParam=type}}
+
{{label}}: {{filterText}}
+ {{fa-icon "times-circle"}}
+ {{/d-button}}
+{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/group-logs-row.hbs b/app/assets/javascripts/discourse/templates/components/group-logs-row.hbs
new file mode 100644
index 00000000000..31d63039952
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/components/group-logs-row.hbs
@@ -0,0 +1,59 @@
+
+
+ {{#d-button class="btn-small" action="filter" actionParam=(hash value=log.action key="action")}}
+ {{log.actionTitle}}
+ {{/d-button}}
+ |
+
+
+ {{avatar log.acting_user imageSize='tiny'}}
+
+ {{#d-button class="btn-small" action="filter" actionParam=(hash value=log.acting_user.username key="acting_user")}}
+ {{log.acting_user.username}}
+ {{/d-button}}
+ |
+
+
+ {{#if log.target_user}}
+ {{avatar log.target_user imageSize='tiny'}}
+
+ {{#d-button class="btn-small" action="filter" actionParam=(hash value=log.target_user.username key="target_user")}}
+ {{log.target_user.username}}
+ {{/d-button}}
+ {{/if}}
+ |
+
+
+ {{#if log.subject}}
+ {{#d-button class="btn-small" action="filter" actionParam=(hash value=log.subject key="subject")}}
+ {{log.subject}}
+ {{/d-button}}
+ {{/if}}
+ |
+
+ {{bound-date log.created_at}} |
+
+
+ {{#if log.prev_value}}
+ {{#if expandDetails}}
+ {{fa-icon 'ellipsis-v'}}
+ {{else}}
+ {{fa-icon 'ellipsis-h'}}
+ {{/if}}
+ {{/if}}
+ |
+
+
+{{#if expandDetails}}
+
+
+
+ {{i18n 'groups.logs.from'}}: {{log.prev_value}}
+
+
+
+ {{i18n 'groups.logs.to'}}: {{log.new_value}}
+
+ |
+
+{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/group-index.hbs b/app/assets/javascripts/discourse/templates/group-index.hbs
index 7ccbf6ea1c6..694750e6821 100644
--- a/app/assets/javascripts/discourse/templates/group-index.hbs
+++ b/app/assets/javascripts/discourse/templates/group-index.hbs
@@ -4,6 +4,20 @@
{{user-selector usernames=usernames placeholderKey="groups.selector_placeholder" id="user-search-selector" name="usernames"}}
{{d-button action="addMembers" class="add" icon="plus" label="groups.add"}}
+ {{else if canJoinGroup}}
+ {{#if model.is_group_user}}
+ {{d-button action="leaveGroup"
+ class="btn-danger group-index-leave"
+ icon="minus"
+ label="groups.leave"
+ disabled=updatingMembership}}
+ {{else}}
+ {{d-button action="joinGroup"
+ class="group-index-join"
+ icon="plus"
+ label="groups.join"
+ disabled=updatingMembership}}
+ {{/if}}
{{/if}}
{{#load-more selector=".group-members tr" action="loadMore"}}
diff --git a/app/assets/javascripts/discourse/templates/group-logs.hbs b/app/assets/javascripts/discourse/templates/group-logs.hbs
new file mode 100644
index 00000000000..a43424da344
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/group-logs.hbs
@@ -0,0 +1,33 @@
+{{#if model}}
+
+ {{group-logs-filter clearFilter="clearFilter" value=filters.action type="action"}}
+ {{group-logs-filter clearFilter="clearFilter" value=filters.acting_user type="acting_user"}}
+ {{group-logs-filter clearFilter="clearFilter" value=filters.target_user type="target_user"}}
+ {{group-logs-filter clearFilter="clearFilter" value=filters.subject type="subject"}}
+
+
+ {{#load-more selector=".group-logs .group-logs-row" action="loadMore"}}
+
+
+ {{i18n 'groups.logs.action'}} |
+ {{i18n 'groups.logs.acting_user'}} |
+ {{i18n 'groups.logs.target_user'}} |
+ {{i18n 'groups.logs.subject'}} |
+ {{i18n 'groups.logs.when'}} |
+ |
+
+
+
+ {{#each model.logs as |log|}}
+ {{group-logs-row
+ log=log
+ filters=filters}}
+ {{/each}}
+
+
+ {{/load-more}}
+
+ {{conditional-loading-spinner condition=loading}}
+{{else}}
+
{{i18n "groups.empty.logs"}}
+{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/group.hbs b/app/assets/javascripts/discourse/templates/group.hbs
index fac08c84288..f7188592d2b 100644
--- a/app/assets/javascripts/discourse/templates/group.hbs
+++ b/app/assets/javascripts/discourse/templates/group.hbs
@@ -23,7 +23,7 @@
{{#if canEditGroup}}
- {{d-button action="showGroupEditor" label="group.edit.title" class="group-edit-btn" icon="pencil"}}
+ {{d-button action="showGroupEditor" label="groups.edit.title" class="group-edit-btn" icon="pencil"}}
{{/if}}
@@ -41,6 +41,7 @@
{{#each getTabs as |tab|}}