mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
FEATURE: invite page tabs
This commit is contained in:
parent
84549929ba
commit
e0c9054748
27 changed files with 170 additions and 93 deletions
|
@ -4,26 +4,26 @@
|
|||
<div class="full-width">
|
||||
|
||||
<ul class="nav nav-pills">
|
||||
{{admin-nav-item route='admin.dashboard' label='admin.dashboard.title'}}
|
||||
{{nav-item route='admin.dashboard' label='admin.dashboard.title'}}
|
||||
{{#if currentUser.admin}}
|
||||
{{admin-nav-item route='adminSiteSettings' label='admin.site_settings.title'}}
|
||||
{{nav-item route='adminSiteSettings' label='admin.site_settings.title'}}
|
||||
{{/if}}
|
||||
{{admin-nav-item route='adminUsersList.show' routeParam='active' label='admin.users.title'}}
|
||||
{{nav-item route='adminUsersList.show' routeParam='active' label='admin.users.title'}}
|
||||
{{#if showBadges}}
|
||||
{{admin-nav-item route='adminBadges.index' label='admin.badges.title'}}
|
||||
{{nav-item route='adminBadges.index' label='admin.badges.title'}}
|
||||
{{/if}}
|
||||
{{#if currentUser.admin}}
|
||||
{{admin-nav-item route='adminGroups' label='admin.groups.title'}}
|
||||
{{nav-item route='adminGroups' label='admin.groups.title'}}
|
||||
{{/if}}
|
||||
{{admin-nav-item route='adminEmail' label='admin.email.title'}}
|
||||
{{admin-nav-item route='adminFlags' label='admin.flags.title'}}
|
||||
{{admin-nav-item route='adminLogs' label='admin.logs.title'}}
|
||||
{{nav-item route='adminEmail' label='admin.email.title'}}
|
||||
{{nav-item route='adminFlags' label='admin.flags.title'}}
|
||||
{{nav-item route='adminLogs' label='admin.logs.title'}}
|
||||
{{#if currentUser.admin}}
|
||||
{{admin-nav-item route='adminCustomize.colors' label='admin.customize.title'}}
|
||||
{{admin-nav-item route='admin.api' label='admin.api.title'}}
|
||||
{{admin-nav-item route='admin.backups' label='admin.backups.title'}}
|
||||
{{nav-item route='adminCustomize.colors' label='admin.customize.title'}}
|
||||
{{nav-item route='admin.api' label='admin.api.title'}}
|
||||
{{nav-item route='admin.backups' label='admin.backups.title'}}
|
||||
{{/if}}
|
||||
{{admin-nav-item route='adminPlugins' label='admin.plugins.title'}}
|
||||
{{nav-item route='adminPlugins' label='admin.plugins.title'}}
|
||||
{{plugin-outlet "admin-menu" tagName="li"}}
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<div class="admin-controls">
|
||||
<div class="span15">
|
||||
<ul class="nav nav-pills">
|
||||
{{admin-nav-item route='admin.backups.index' label='admin.backups.menu.backups'}}
|
||||
{{admin-nav-item route='admin.backups.logs' label='admin.backups.menu.logs'}}
|
||||
{{nav-item route='admin.backups.index' label='admin.backups.menu.backups'}}
|
||||
{{nav-item route='admin.backups.logs' label='admin.backups.menu.logs'}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminCustomize.colors' label='admin.customize.colors.title'}}
|
||||
{{admin-nav-item route='adminCustomize.css_html' label='admin.customize.css_html.title'}}
|
||||
{{admin-nav-item route='adminSiteText' label='admin.site_text.title'}}
|
||||
{{admin-nav-item route='adminUserFields' label='admin.user_fields.title'}}
|
||||
{{admin-nav-item route='adminEmojis' label='admin.emoji.title'}}
|
||||
{{nav-item route='adminCustomize.colors' label='admin.customize.colors.title'}}
|
||||
{{nav-item route='adminCustomize.css_html' label='admin.customize.css_html.title'}}
|
||||
{{nav-item route='adminSiteText' label='admin.site_text.title'}}
|
||||
{{nav-item route='adminUserFields' label='admin.user_fields.title'}}
|
||||
{{nav-item route='adminEmojis' label='admin.emoji.title'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminEmail.index' label='admin.email.settings'}}
|
||||
{{admin-nav-item route='adminEmail.all' label='admin.email.all'}}
|
||||
{{admin-nav-item route='adminEmail.sent' label='admin.email.sent'}}
|
||||
{{admin-nav-item route='adminEmail.skipped' label='admin.email.skipped'}}
|
||||
{{admin-nav-item route='adminEmail.previewDigest' label='admin.email.preview_digest'}}
|
||||
{{nav-item route='adminEmail.index' label='admin.email.settings'}}
|
||||
{{nav-item route='adminEmail.all' label='admin.email.all'}}
|
||||
{{nav-item route='adminEmail.sent' label='admin.email.sent'}}
|
||||
{{nav-item route='adminEmail.skipped' label='admin.email.skipped'}}
|
||||
{{nav-item route='adminEmail.previewDigest' label='admin.email.preview_digest'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminFlags.list' routeParam='active' label='admin.flags.active'}}
|
||||
{{admin-nav-item route='adminFlags.list' routeParam='old' label='admin.flags.old'}}
|
||||
{{nav-item route='adminFlags.list' routeParam='active' label='admin.flags.active'}}
|
||||
{{nav-item route='adminFlags.list' routeParam='old' label='admin.flags.old'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminGroupsType' routeParam='custom' label='admin.groups.custom'}}
|
||||
{{admin-nav-item route='adminGroupsType' routeParam='automatic' label='admin.groups.automatic'}}
|
||||
{{nav-item route='adminGroupsType' routeParam='custom' label='admin.groups.custom'}}
|
||||
{{nav-item route='adminGroupsType' routeParam='automatic' label='admin.groups.automatic'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
<div class="admin-container">
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{{#admin-nav}}
|
||||
{{admin-nav-item route='adminLogs.staffActionLogs' label='admin.logs.staff_actions.title'}}
|
||||
{{admin-nav-item route='adminLogs.screenedEmails' label='admin.logs.screened_emails.title'}}
|
||||
{{admin-nav-item route='adminLogs.screenedIpAddresses' label='admin.logs.screened_ips.title'}}
|
||||
{{admin-nav-item route='adminLogs.screenedUrls' label='admin.logs.screened_urls.title'}}
|
||||
{{nav-item route='adminLogs.staffActionLogs' label='admin.logs.staff_actions.title'}}
|
||||
{{nav-item route='adminLogs.screenedEmails' label='admin.logs.screened_emails.title'}}
|
||||
{{nav-item route='adminLogs.screenedIpAddresses' label='admin.logs.screened_ips.title'}}
|
||||
{{nav-item route='adminLogs.screenedUrls' label='admin.logs.screened_urls.title'}}
|
||||
{{#if currentUser.admin}}
|
||||
{{admin-nav-item path='/logs' label='admin.logs.logster.title'}}
|
||||
{{nav-item path='/logs' label='admin.logs.logster.title'}}
|
||||
{{/if}}
|
||||
{{/admin-nav}}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<div class="admin-nav pull-left">
|
||||
<ul class="nav nav-stacked">
|
||||
{{admin-nav-item route='adminPlugins.index' label="admin.plugins.title"}}
|
||||
{{nav-item route='adminPlugins.index' label="admin.plugins.title"}}
|
||||
|
||||
{{#each route in adminRoutes}}
|
||||
{{admin-nav-item route=route.full_location label=route.label}}
|
||||
{{nav-item route=route.full_location label=route.label}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<div class='admin-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
{{admin-nav-item route='adminUsersList.show' routeParam='active' label='admin.users.nav.active'}}
|
||||
{{admin-nav-item route='adminUsersList.show' routeParam='new' label='admin.users.nav.new'}}
|
||||
{{nav-item route='adminUsersList.show' routeParam='active' label='admin.users.nav.active'}}
|
||||
{{nav-item route='adminUsersList.show' routeParam='new' label='admin.users.nav.new'}}
|
||||
{{#if siteSettings.must_approve_users}}
|
||||
{{admin-nav-item route='adminUsersList.show' routeParam='pending' label='admin.users.nav.pending'}}
|
||||
{{nav-item route='adminUsersList.show' routeParam='pending' label='admin.users.nav.pending'}}
|
||||
{{/if}}
|
||||
{{admin-nav-item route='adminUsersList.show' routeParam='staff' label='admin.users.nav.staff'}}
|
||||
{{admin-nav-item route='adminUsersList.show' routeParam='suspended' label='admin.users.nav.suspended'}}
|
||||
{{admin-nav-item route='adminUsersList.show' routeParam='blocked' label='admin.users.nav.blocked'}}
|
||||
{{admin-nav-item route='adminUsersList.show' routeParam='suspect' label='admin.users.nav.suspect'}}
|
||||
{{nav-item route='adminUsersList.show' routeParam='staff' label='admin.users.nav.staff'}}
|
||||
{{nav-item route='adminUsersList.show' routeParam='suspended' label='admin.users.nav.suspended'}}
|
||||
{{nav-item route='adminUsersList.show' routeParam='blocked' label='admin.users.nav.blocked'}}
|
||||
{{nav-item route='adminUsersList.show' routeParam='suspect' label='admin.users.nav.suspect'}}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
|
|
|
@ -3,7 +3,7 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
|||
import ObjectController from 'discourse/controllers/object';
|
||||
|
||||
export default ObjectController.extend(Presence, ModalFunctionality, {
|
||||
needs: ['user-invited'],
|
||||
needs: ['user-invited-show'],
|
||||
|
||||
// If this isn't defined, it will proxy to the user model on the preferences
|
||||
// page which is wrong.
|
||||
|
@ -132,14 +132,14 @@ export default ObjectController.extend(Presence, ModalFunctionality, {
|
|||
if (this.get('disabled')) { return; }
|
||||
|
||||
const groupNames = this.get('groupNames'),
|
||||
userInvitedController = this.get('controllers.user-invited');
|
||||
userInvitedController = this.get('controllers.user-invited-show');
|
||||
|
||||
this.setProperties({ saving: true, error: false });
|
||||
|
||||
return this.get('model').createInvite(this.get('emailOrUsername').trim(), groupNames).then(result => {
|
||||
this.setProperties({ saving: false, finished: true });
|
||||
if (!this.get('invitingToTopic')) {
|
||||
Discourse.Invite.findInvitedBy(Discourse.User.current()).then(invite_model => {
|
||||
Discourse.Invite.findInvitedBy(Discourse.User.current(), userInvitedController.get('filter')).then(invite_model => {
|
||||
userInvitedController.set('model', invite_model);
|
||||
userInvitedController.set('totalInvites', invite_model.invites.length);
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
export default Ember.ObjectController.extend({
|
||||
user: null,
|
||||
model: null,
|
||||
filter: null,
|
||||
totalInvites: null,
|
||||
canLoadMore: true,
|
||||
invitesLoading: false,
|
||||
|
@ -20,11 +21,13 @@ export default Ember.ObjectController.extend({
|
|||
**/
|
||||
_searchTermChanged: Discourse.debounce(function() {
|
||||
var self = this;
|
||||
Discourse.Invite.findInvitedBy(self.get('user'), this.get('searchTerm')).then(function (invites) {
|
||||
Discourse.Invite.findInvitedBy(self.get('user'), this.get('filter'), this.get('searchTerm')).then(function (invites) {
|
||||
self.set('model', invites);
|
||||
});
|
||||
}, 250).observes('searchTerm'),
|
||||
|
||||
inviteRedeemed: Em.computed.equal('filter', 'redeemed'),
|
||||
|
||||
/**
|
||||
Can the currently logged in user invite users to the site
|
||||
|
||||
|
@ -82,7 +85,7 @@ export default Ember.ObjectController.extend({
|
|||
|
||||
if (self.get('canLoadMore') && !self.get('invitesLoading')) {
|
||||
self.set('invitesLoading', true);
|
||||
Discourse.Invite.findInvitedBy(self.get('user'), self.get('searchTerm'), model.invites.length).then(function(invite_model) {
|
||||
Discourse.Invite.findInvitedBy(self.get('user'), self.get('filter'), self.get('searchTerm'), model.invites.length).then(function(invite_model) {
|
||||
self.set('invitesLoading', false);
|
||||
model.invites.pushObjects(invite_model.invites);
|
||||
if(invite_model.invites.length === 0 || invite_model.invites.length < Discourse.SiteSettings.invites_per_page) {
|
|
@ -37,11 +37,12 @@ Discourse.Invite.reopenClass({
|
|||
return result;
|
||||
},
|
||||
|
||||
findInvitedBy: function(user, filter, offset) {
|
||||
findInvitedBy: function(user, filter, search, offset) {
|
||||
if (!user) { return Em.RSVP.resolve(); }
|
||||
|
||||
var data = {};
|
||||
if (!Em.isNone(filter)) { data.filter = filter; }
|
||||
if (!Em.isNone(search)) { data.search = search; }
|
||||
data.offset = offset || 0;
|
||||
|
||||
return Discourse.ajax("/users/" + user.get('username_lower') + "/invited.json", {data: data}).then(function (result) {
|
||||
|
|
|
@ -79,7 +79,9 @@ export default function() {
|
|||
this.route('card-badge', { path: '/card-badge' });
|
||||
});
|
||||
|
||||
this.route('invited');
|
||||
this.resource('userInvited', { path: '/invited' }, function() {
|
||||
this.route('show', { path: '/:filter' });
|
||||
});
|
||||
});
|
||||
|
||||
this.route('signup', {path: '/signup'});
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export default Discourse.Route.extend({
|
||||
beforeModel: function() {
|
||||
this.replaceWith('userInvited.show', 'redeemed');
|
||||
}
|
||||
});
|
|
@ -2,18 +2,17 @@ import ShowFooter from 'discourse/mixins/show-footer';
|
|||
import showModal from 'discourse/lib/show-modal';
|
||||
|
||||
export default Discourse.Route.extend(ShowFooter, {
|
||||
renderTemplate() {
|
||||
this.render({ into: 'user' });
|
||||
},
|
||||
|
||||
model() {
|
||||
return Discourse.Invite.findInvitedBy(this.modelFor('user'));
|
||||
model: function(params) {
|
||||
this.inviteFilter = params.filter;
|
||||
return Discourse.Invite.findInvitedBy(this.modelFor('user'), params.filter);
|
||||
},
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.setProperties({
|
||||
model: model,
|
||||
user: this.controllerFor('user').get('model'),
|
||||
filter: this.inviteFilter,
|
||||
searchTerm: '',
|
||||
totalInvites: model.invites.length
|
||||
});
|
|
@ -1,32 +1,46 @@
|
|||
{{#if canInviteToForum}}
|
||||
<section class='user-content'>
|
||||
|
||||
<h2>{{i18n 'user.invited.title'}}</h2>
|
||||
|
||||
<div class="pull-right">
|
||||
<button {{action "showInvite"}} class='btn'>{{i18n 'user.invited.create'}}</button>
|
||||
{{#if canBulkInvite}}
|
||||
{{resumable-upload target="/invites/upload" success="uploadSuccess" error="uploadError" uploadText=uploadText}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if can_see_invite_details}}
|
||||
<div class='user-invite-controls'>
|
||||
<div class='span15'>
|
||||
<ul class="nav nav-pills">
|
||||
{{nav-item route='userInvited.show' routeParam='redeemed' label='user.invited.redeemed_tab'}}
|
||||
{{nav-item route='userInvited.show' routeParam='pending' label='user.invited.pending_tab'}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="pull-right">
|
||||
{{d-button action="showInvite" label='user.invited.create' class='btn'}}
|
||||
{{#if canBulkInvite}}
|
||||
{{resumable-upload target="/invites/upload" success="uploadSuccess" error="uploadError" uploadText=uploadText}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if showSearch}}
|
||||
<form>
|
||||
{{text-field value=searchTerm placeholderKey="user.invited.search"}}
|
||||
</form>
|
||||
<div class="user-invite-search">
|
||||
<form>{{text-field value=searchTerm placeholderKey="user.invited.search"}}</form>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if model.invites}}
|
||||
<table class='table invite-list'>
|
||||
<table class='table user-invite-list'>
|
||||
<tr>
|
||||
<th>{{i18n 'user.invited.user'}}</th>
|
||||
<th>{{i18n 'user.invited.redeemed_at'}}</th>
|
||||
{{#if can_see_invite_details}}
|
||||
<th>{{i18n 'user.last_seen'}}</th>
|
||||
<th>{{i18n 'user.invited.topics_entered'}}</th>
|
||||
<th>{{i18n 'user.invited.posts_read_count'}}</th>
|
||||
<th>{{i18n 'user.invited.time_read'}}</th>
|
||||
<th>{{i18n 'user.invited.days_visited'}}</th>
|
||||
{{#if inviteRedeemed}}
|
||||
<th>{{i18n 'user.invited.user'}}</th>
|
||||
<th>{{i18n 'user.invited.redeemed_at'}}</th>
|
||||
{{#if can_see_invite_details}}
|
||||
<th>{{i18n 'user.last_seen'}}</th>
|
||||
<th>{{i18n 'user.invited.topics_entered'}}</th>
|
||||
<th>{{i18n 'user.invited.posts_read_count'}}</th>
|
||||
<th>{{i18n 'user.invited.time_read'}}</th>
|
||||
<th>{{i18n 'user.invited.days_visited'}}</th>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<th colspan="7">{{i18n 'user.invited.user'}}</th>
|
||||
{{/if}}
|
||||
</tr>
|
||||
{{#each invite in model.invites}}
|
||||
|
@ -56,13 +70,13 @@
|
|||
{{#if invite.rescinded}}
|
||||
{{i18n 'user.invited.rescinded'}}
|
||||
{{else}}
|
||||
<button class='btn' {{action "rescind" invite}}><i class="fa fa-times"></i>{{i18n 'user.invited.rescind'}}</button>
|
||||
{{d-button icon="times" action="rescind" actionParam=invite class="btn" label="user.invited.rescind"}}
|
||||
{{/if}}
|
||||
|
||||
{{#if invite.reinvited}}
|
||||
{{i18n 'user.invited.reinvited'}}
|
||||
{{else}}
|
||||
<button class='btn' {{action "reinvite" invite}}><i class="fa fa-user-plus"></i>{{i18n 'user.invited.reinvite'}}</button>
|
||||
{{d-button icon="user-plus" action="reinvite" actionParam=invite class="btn" label="user.invited.reinvite"}}
|
||||
{{/if}}
|
||||
</td>
|
||||
{{/if}}
|
||||
|
@ -72,12 +86,13 @@
|
|||
{{conditional-loading-spinner condition=invitesLoading}}
|
||||
|
||||
{{else}}
|
||||
{{#if canBulkInvite}}
|
||||
{{{i18n 'user.invited.bulk_invite.none'}}}
|
||||
{{else}}
|
||||
{{i18n 'user.invited.none'}}
|
||||
{{/if}}
|
||||
<div class="user-invite-none">
|
||||
{{#if canBulkInvite}}
|
||||
{{{i18n 'user.invited.bulk_invite.none'}}}
|
||||
{{else}}
|
||||
{{i18n 'user.invited.none'}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
</section>
|
||||
{{/if}}
|
|
@ -55,7 +55,7 @@
|
|||
<li>{{#link-to 'preferences' class="btn right"}}{{fa-icon "cog"}}{{i18n 'user.preferences'}}{{/link-to}}</li>
|
||||
{{/if}}
|
||||
{{#if canInviteToForum}}
|
||||
<li>{{#link-to 'user.invited' class="btn right"}}{{fa-icon "user-plus"}}{{i18n 'user.invited.title'}}{{/link-to}}</li>
|
||||
<li>{{#link-to 'userInvited' class="btn right"}}{{fa-icon "user-plus"}}{{i18n 'user.invited.title'}}{{/link-to}}</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</section>
|
||||
|
|
|
@ -2,6 +2,6 @@ import LoadMore from "discourse/mixins/load-more";
|
|||
|
||||
export default Ember.View.extend(LoadMore, {
|
||||
classNames: ['paginated-topics-list'],
|
||||
eyelineSelector: '.paginated-topics-list .invite-list tr',
|
||||
templateName: 'user/invited'
|
||||
eyelineSelector: '.paginated-topics-list .user-invite-list tr',
|
||||
templateName: 'user-invited-show'
|
||||
});
|
|
@ -184,6 +184,26 @@
|
|||
max-height: 45px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-invite-list {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.user-invite-controls {
|
||||
background-color: dark-light-diff($primary, $secondary, 90%, -75%);
|
||||
padding: 5px 10px 0px 0;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.user-invite-search {
|
||||
clear: both;
|
||||
margin: 15px 0px -15px 0px;
|
||||
}
|
||||
|
||||
.user-invite-none {
|
||||
clear: both;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.about {
|
||||
|
|
|
@ -168,14 +168,15 @@ class UsersController < ApplicationController
|
|||
def invited
|
||||
inviter = fetch_user_from_params
|
||||
offset = params[:offset].to_i || 0
|
||||
filter_by = params[:filter]
|
||||
|
||||
invites = if guardian.can_see_invite_details?(inviter)
|
||||
Invite.find_all_invites_from(inviter, offset)
|
||||
invites = if guardian.can_see_invite_details?(inviter) && filter_by == "pending"
|
||||
Invite.find_pending_invites_from(inviter, offset)
|
||||
else
|
||||
Invite.find_redeemed_invites_from(inviter, offset)
|
||||
end
|
||||
|
||||
invites = invites.filter_by(params[:filter])
|
||||
invites = invites.filter_by(params[:search])
|
||||
render_json_dump invites: serialize_data(invites.to_a, InviteSerializer),
|
||||
can_see_invite_details: guardian.can_see_invite_details?(inviter)
|
||||
end
|
||||
|
|
|
@ -162,8 +162,12 @@ class Invite < ActiveRecord::Base
|
|||
.references('user_stats')
|
||||
end
|
||||
|
||||
def self.find_pending_invites_from(inviter, offset=0)
|
||||
find_all_invites_from(inviter, offset).where('invites.user_id IS NULL').order('invites.created_at DESC')
|
||||
end
|
||||
|
||||
def self.find_redeemed_invites_from(inviter, offset=0)
|
||||
find_all_invites_from(inviter, offset).where('invites.user_id IS NOT NULL')
|
||||
find_all_invites_from(inviter, offset).where('invites.user_id IS NOT NULL').order('invites.redeemed_at DESC')
|
||||
end
|
||||
|
||||
def self.filter_by(email_or_username)
|
||||
|
|
|
@ -572,8 +572,10 @@ en:
|
|||
none: "You haven't invited anyone here yet."
|
||||
truncated: "Showing the first {{count}} invites."
|
||||
redeemed: "Redeemed Invites"
|
||||
redeemed_tab: "Redeemed"
|
||||
redeemed_at: "Redeemed"
|
||||
pending: "Pending Invites"
|
||||
pending_tab: "Pending"
|
||||
topics_entered: "Topics Viewed"
|
||||
posts_read_count: "Posts Read"
|
||||
expired: "This invite has expired."
|
||||
|
|
|
@ -268,6 +268,7 @@ Discourse::Application.routes.draw do
|
|||
get "users/:username/staff-info" => "users#staff_info", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
|
||||
get "users/:username/invited" => "users#invited", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
get "users/:username/invited/:filter" => "users#invited", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
post "users/action/send_activation_email" => "users#send_activation_email"
|
||||
get "users/:username/activity" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
get "users/:username/activity/:filter" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||
|
|
|
@ -911,7 +911,7 @@ describe UsersController do
|
|||
user: invitee
|
||||
)
|
||||
|
||||
xhr :get, :invited, username: inviter.username, filter: 'billybob'
|
||||
xhr :get, :invited, username: inviter.username, search: 'billybob'
|
||||
|
||||
invites = JSON.parse(response.body)['invites']
|
||||
expect(invites.size).to eq(1)
|
||||
|
@ -933,7 +933,7 @@ describe UsersController do
|
|||
user: Fabricate(:user, username: 'jimtom')
|
||||
)
|
||||
|
||||
xhr :get, :invited, username: inviter.username, filter: 'billybob'
|
||||
xhr :get, :invited, username: inviter.username, search: 'billybob'
|
||||
|
||||
invites = JSON.parse(response.body)['invites']
|
||||
expect(invites.size).to eq(1)
|
||||
|
@ -946,7 +946,7 @@ describe UsersController do
|
|||
inviter = Fabricate(:user)
|
||||
Fabricate(:invite, invited_by: inviter)
|
||||
|
||||
xhr :get, :invited, username: inviter.username
|
||||
xhr :get, :invited, username: inviter.username, filter: 'pending'
|
||||
|
||||
invites = JSON.parse(response.body)['invites']
|
||||
expect(invites).to be_empty
|
||||
|
@ -980,7 +980,7 @@ describe UsersController do
|
|||
with(inviter).returns(true)
|
||||
end
|
||||
|
||||
xhr :get, :invited, username: inviter.username
|
||||
xhr :get, :invited, username: inviter.username, filter: 'pending'
|
||||
|
||||
invites = JSON.parse(response.body)['invites']
|
||||
expect(invites.size).to eq(1)
|
||||
|
@ -999,7 +999,7 @@ describe UsersController do
|
|||
with(inviter).returns(false)
|
||||
end
|
||||
|
||||
xhr :get, :invited, username: inviter.username
|
||||
xhr :get, :invited, username: inviter.username, filter: 'pending'
|
||||
|
||||
json = JSON.parse(response.body)['invites']
|
||||
expect(json).to be_empty
|
||||
|
|
|
@ -387,6 +387,30 @@ describe Invite do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.find_pending_invites_from' do
|
||||
it 'returns pending invites only' do
|
||||
inviter = Fabricate(:user)
|
||||
Fabricate(
|
||||
:invite,
|
||||
invited_by: inviter,
|
||||
user_id: 123,
|
||||
email: 'redeemed@example.com'
|
||||
)
|
||||
|
||||
pending_invite = Fabricate(
|
||||
:invite,
|
||||
invited_by: inviter,
|
||||
user_id: nil,
|
||||
email: 'pending@example.com'
|
||||
)
|
||||
|
||||
invites = Invite.find_pending_invites_from(inviter)
|
||||
|
||||
expect(invites.size).to eq(1)
|
||||
expect(invites.first).to eq pending_invite
|
||||
end
|
||||
end
|
||||
|
||||
describe '.find_redeemed_invites_from' do
|
||||
it 'returns redeemed invites only' do
|
||||
inviter = Fabricate(:user)
|
||||
|
|
Loading…
Reference in a new issue