Teams/Organizations to Admin Panel. In Progress.

Thanks to xet7 !

Related #802
This commit is contained in:
Lauri Ojansivu 2020-12-28 21:08:27 +02:00
parent b7137e617e
commit 9e2093d6ae
8 changed files with 684 additions and 53 deletions

View file

@ -5,28 +5,95 @@ template(name="people")
else else
.content-title.ext-box .content-title.ext-box
.ext-box-left .ext-box-left
span if loading.get
i.fa.fa-users +spinner
| {{_ 'people'}} else if orgSetting.get
input#searchInput(placeholder="{{_ 'search'}}") span
button#searchButton i.fa.fa-sitemap
i.fa.fa-search | {{_ 'organizations'}}
| {{_ 'search'}} input#searchOrgInput(placeholder="{{_ 'search'}}")
.ext-box-right button#searchOrgButton
span {{_ 'people-number'}} #{peopleNumber} i.fa.fa-search
| {{_ 'search'}}
.ext-box-right
span {{_ 'org-number'}} #{orgNumber}
else if teamSetting.get
span
i.fa.fa-users
| {{_ 'teams'}}
input#searchTeamInput(placeholder="{{_ 'search'}}")
button#searchTeamButton
i.fa.fa-search
| {{_ 'search'}}
.ext-box-right
span {{_ 'team-number'}} #{teamNumber}
else if peopleSetting.get
span
i.fa.fa-user
| {{_ 'people'}}
input#searchInput(placeholder="{{_ 'search'}}")
button#searchButton
i.fa.fa-search
| {{_ 'search'}}
.ext-box-right
span {{_ 'people-number'}} #{peopleNumber}
.content-body .content-body
.side-menu .side-menu
ul ul
li.active li.active
a.js-setting-menu(data-id="people-setting") a.js-org-menu(data-id="org-setting")
i.fa.fa-sitemap
| {{_ 'organizations'}}
li
a.js-team-menu(data-id="team-setting")
i.fa.fa-users i.fa.fa-users
| {{_ 'teams'}}
li
a.js-people-menu(data-id="people-setting")
i.fa.fa-user
| {{_ 'people'}} | {{_ 'people'}}
.main-body .main-body
if loading.get if loading.get
+spinner +spinner
else if people.get else if orgSetting.get
+orgGeneral
else if teamSetting.get
+teamGeneral
else if peopleSetting.get
+peopleGeneral +peopleGeneral
template(name="orgGeneral")
table
tbody
tr
th {{_ 'displayName'}}
th {{_ 'description'}}
th {{_ 'shortName'}}
th {{_ 'website'}}
th {{_ 'teams'}}
th {{_ 'createdAt'}}
th {{_ 'active'}}
th
+newOrgRow
each user in orgList
+orgRow(orgId=org._id)
template(name="teamGeneral")
table
tbody
tr
th {{_ 'displayName'}}
th {{_ 'description'}}
th {{_ 'shortName'}}
th {{_ 'website'}}
th {{_ 'createdAt'}}
th {{_ 'active'}}
th
+newTeamRow
each team in teamList
+teamRow(teamId=team._id)
template(name="peopleGeneral") template(name="peopleGeneral")
table table
tbody tbody
@ -44,11 +111,93 @@ template(name="peopleGeneral")
each user in peopleList each user in peopleList
+peopleRow(userId=user._id) +peopleRow(userId=user._id)
template(name="newOrgRow")
a.new-org
i.fa.fa-edit
| {{_ 'new'}}
template(name="newTeamRow")
a.new-team
i.fa.fa-edit
| {{_ 'new'}}
template(name="newUserRow") template(name="newUserRow")
a.new-user a.new-user
i.fa.fa-edit i.fa.fa-edit
| {{_ 'new'}} | {{_ 'new'}}
template(name="orgRow")
tr
if orgData.loginDisabled
td <s>{{ orgData.displayName }}</s>
else
td {{ orgData.displayName }}
if orgData.loginDisabled
td <s>{{ orgData.orgDesc }}</s>
else
td {{ orgData.desc }}
if orgData.loginDisabled
td <s>{{ orgData.name }}</s>
else
td {{ orgData.name }}
if orgData.loginDisabled
td <s>{{ orgData.website }}</s>
else
td {{ orgData.website }}
if orgData.loginDisabled
td <s>{{ orgData.teams }}</s>
else
td {{ orgData.teams }}
if orgData.loginDisabled
td <s>{{ moment orgData.createdAt 'LLL' }}</s>
else
td {{ moment orgData.createdAt 'LLL' }}
td
if orgData.loginDisabled
| {{_ 'no'}}
else
| {{_ 'yes'}}
td
a.edit-org
i.fa.fa-edit
| {{_ 'edit'}}
a.more-settings-org
i.fa.fa-ellipsis-h
template(name="teamRow")
tr
if teamData.loginDisabled
td <s>{{ teamData.displayName }}</s>
else
td {{ teamData.displayName }}
if teamData.loginDisabled
td <s>{{ teamData.desc }}</s>
else
td {{ teamData.desc }}
if teamData.loginDisabled
td <s>{{ teamData.dame }}</s>
else
td {{ teamData.name }}
if teamData.loginDisabled
td <s>{{ teamData.website }}</s>
else
td {{ teamData.website }}
if orgData.loginDisabled
td <s>{{ moment teamData.createdAt 'LLL' }}</s>
else
td {{ moment teamData.createdAt 'LLL' }}
td
if teamData.loginDisabled
| {{_ 'no'}}
else
| {{_ 'yes'}}
td
a.edit-team
i.fa.fa-edit
| {{_ 'edit'}}
a.more-settings-team
i.fa.fa-ellipsis-h
template(name="peopleRow") template(name="peopleRow")
tr tr
if userData.loginDisabled if userData.loginDisabled
@ -107,6 +256,58 @@ template(name="peopleRow")
a.more-settings-user a.more-settings-user
i.fa.fa-ellipsis-h i.fa.fa-ellipsis-h
template(name="editOrgPopup")
form
label.hide.orgId(type="text" value=org._id)
label
| {{_ 'orgDisplayName'}}
input.js-orgDisplayName(type="text" value=org.orgDisplayName required)
span.error.hide.orgname-taken
| {{_ 'error-orgname-taken'}}
label
| {{_ 'orgDesc'}}
input.js-orgDesc(type="text" value=org.orgDesc required)
label
| {{_ 'orgName'}}
input.js-orgName(type="text" value=org.orgName required)
label
| {{_ 'orgWebsite'}}
input.js-orgWebsite(type="text" value=org.orgWebsite required)
label
| {{_ 'active'}}
select.select-active.js-org-isactive
option(value="false") {{_ 'yes'}}
option(value="true" selected="{{org.loginDisabled}}") {{_ 'no'}}
hr
div.buttonsContainer
input.primary.wide(type="submit" value="{{_ 'save'}}")
template(name="editTeamPopup")
form
label.hide.teamId(type="text" value=team._id)
label
| {{_ 'displayName'}}
input.js-teamDisplayName(type="text" value=team.displayName required)
span.error.hide.teamname-taken
| {{_ 'error-teamname-taken'}}
label
| {{_ 'desc'}}
input.js-orgDesc(type="text" value=org.desc required)
label
| {{_ 'name'}}
input.js-orgName(type="text" value=org.name required)
label
| {{_ 'website'}}
input.js-orgWebsite(type="text" value=org.website required)
label
| {{_ 'active'}}
select.select-active.js-team-isactive
option(value="false") {{_ 'yes'}}
option(value="true" selected="{{team.loginDisabled}}") {{_ 'no'}}
hr
div.buttonsContainer
input.primary.wide(type="submit" value="{{_ 'save'}}")
template(name="editUserPopup") template(name="editUserPopup")
form form
label.hide.userId(type="text" value=user._id) label.hide.userId(type="text" value=user._id)
@ -154,6 +355,54 @@ template(name="editUserPopup")
div.buttonsContainer div.buttonsContainer
input.primary.wide(type="submit" value="{{_ 'save'}}") input.primary.wide(type="submit" value="{{_ 'save'}}")
template(name="newOrgPopup")
form
//label.hide.userId(type="text" value=user._id)
label
| {{_ 'orgDisplayName'}}
input.js-orgDisplayName(type="text" value="" required)
label
| {{_ 'orgDesc'}}
input.js-orgDesc(type="text" value="" required)
label
| {{_ 'orgName'}}
input.js-orgName(type="text" value="")
label
| {{_ 'orgWebsite'}}
input.js-orgWebsite(type="text" value="")
label
| {{_ 'active'}}
select.select-active.js-profile-isactive
option(value="false" selected="selected") {{_ 'yes'}}
option(value="true") {{_ 'no'}}
hr
div.buttonsContainer
input.primary.wide(type="submit" value="{{_ 'save'}}")
template(name="newTeamPopup")
form
//label.hide.teamId(type="text" value=team._id)
label
| {{_ 'displayName'}}
input.js-teamDisplayName(type="text" value="" required)
label
| {{_ 'desc'}}
input.js-teamDesc(type="text" value="" required)
label
| {{_ 'shortName'}}
input.js-teamName(type="text" value="")
label
| {{_ 'website'}}
input.js-teamWebsite(type="text" value="")
label
| {{_ 'active'}}
select.select-active.js-profile-isactive
option(value="false" selected="selected") {{_ 'yes'}}
option(value="true") {{_ 'no'}}
hr
div.buttonsContainer
input.primary.wide(type="submit" value="{{_ 'save'}}")
template(name="newUserPopup") template(name="newUserPopup")
form form
//label.hide.userId(type="text" value=user._id) //label.hide.userId(type="text" value=user._id)
@ -201,6 +450,31 @@ template(name="newUserPopup")
div.buttonsContainer div.buttonsContainer
input.primary.wide(type="submit" value="{{_ 'save'}}") input.primary.wide(type="submit" value="{{_ 'save'}}")
template(name="settingsOrgPopup")
ul.pop-over-list
li
a.impersonate-org
i.fa.fa-user
| {{_ 'impersonate-org'}}
// Delete is not enabled yet, because it does leave empty user avatars
// to boards: boards members, card members and assignees have
// empty users. See:
// - wekan/client/components/settings/peopleBody.jade deleteButton
// - wekan/client/components/settings/peopleBody.js deleteButton
// - wekan/client/components/sidebar/sidebar.js Popup.afterConfirm('removeMember'
// that does now remove member from board, card members and assignees correctly,
// but that should be used to remove user from all boards similarly
// - wekan/models/users.js Delete is not enabled
//li
// br
// br
// hr
//li
// form
// label.hide.userId(type="text" value=user._id)
// div.buttonsContainer
// input#deleteButton.card-details-red.right.wide(type="button" value="{{_ 'delete'}}")
template(name="settingsUserPopup") template(name="settingsUserPopup")
ul.pop-over-list ul.pop-over-list
li li

View file

@ -1,3 +1,5 @@
const orgsPerPage = 25;
const teamsPerPage = 25;
const usersPerPage = 25; const usersPerPage = 25;
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({
@ -7,17 +9,45 @@ BlazeComponent.extendComponent({
onCreated() { onCreated() {
this.error = new ReactiveVar(''); this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false); this.loading = new ReactiveVar(false);
this.people = new ReactiveVar(true); this.orgSetting = new ReactiveVar(true);
this.teamSetting = new ReactiveVar(true);
this.peopleSetting = new ReactiveVar(true);
this.findOrgsOptions = new ReactiveVar({});
this.findTeamsOptions = new ReactiveVar({});
this.findUsersOptions = new ReactiveVar({}); this.findUsersOptions = new ReactiveVar({});
this.number = new ReactiveVar(0); this.numberOrgs = new ReactiveVar(0);
this.numberTeams = new ReactiveVar(0);
this.numberPeople = new ReactiveVar(0);
this.page = new ReactiveVar(1); this.page = new ReactiveVar(1);
this.loadNextPageLocked = false; this.loadNextPageLocked = false;
this.callFirstWith(null, 'resetNextPeak'); this.callFirstWith(null, 'resetNextPeak');
this.autorun(() => { this.autorun(() => {
const limit = this.page.get() * usersPerPage; const limitOrgs = this.page.get() * orgsPerPage;
const limitTeams = this.page.get() * teamsPerPage;
const limitUsers = this.page.get() * usersPerPage;
this.subscribe('people', this.findUsersOptions.get(), limit, () => { this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {
this.loadNextPageLocked = false;
const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
this.calculateNextPeak();
const nextPeakAfter = this.callFirstWith(null, 'getNextPeak');
if (nextPeakBefore === nextPeakAfter) {
this.callFirstWith(null, 'resetNextPeak');
}
});
this.subscribe('team', this.findTeamsOptions.get(), limitTeams, () => {
this.loadNextPageLocked = false;
const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
this.calculateNextPeak();
const nextPeakAfter = this.callFirstWith(null, 'getNextPeak');
if (nextPeakBefore === nextPeakAfter) {
this.callFirstWith(null, 'resetNextPeak');
}
});
this.subscribe('people', this.findUsersOptions.get(), limitUsers, () => {
this.loadNextPageLocked = false; this.loadNextPageLocked = false;
const nextPeakBefore = this.callFirstWith(null, 'getNextPeak'); const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
this.calculateNextPeak(); this.calculateNextPeak();
@ -31,6 +61,22 @@ BlazeComponent.extendComponent({
events() { events() {
return [ return [
{ {
'click #searchOrgButton'() {
this.filterOrg();
},
'keydown #searchOrgInput'(event) {
if (event.keyCode === 13 && !event.shiftKey) {
this.filterOrg();
}
},
'click #searchTeamButton'() {
this.filterTeam();
},
'keydown #searchTeamInput'(event) {
if (event.keyCode === 13 && !event.shiftKey) {
this.filterTeam();
}
},
'click #searchButton'() { 'click #searchButton'() {
this.filterPeople(); this.filterPeople();
}, },
@ -39,9 +85,18 @@ BlazeComponent.extendComponent({
this.filterPeople(); this.filterPeople();
} }
}, },
'click #newOrgButton'() {
Popup.open('newOrg');
},
'click #newTeamButton'() {
Popup.open('newTeam');
},
'click #newUserButton'() { 'click #newUserButton'() {
Popup.open('newUser'); Popup.open('newUser');
}, },
'click a.js-org-menu': this.switchMenu,
'click a.js-team-menu': this.switchMenu,
'click a.js-people-menu': this.switchMenu,
}, },
]; ];
}, },
@ -84,18 +139,63 @@ BlazeComponent.extendComponent({
setLoading(w) { setLoading(w) {
this.loading.set(w); this.loading.set(w);
}, },
orgList() {
const orgs = Org.find(this.findOrgsOptions.get(), {
fields: { _id: true },
});
this.numberOrgs.set(org.count(false));
return orgs;
},
teamList() {
const teams = Team.find(this.findTeamsOptions.get(), {
fields: { _id: true },
});
this.numberTeams.set(team.count(false));
return teams;
},
peopleList() { peopleList() {
const users = Users.find(this.findUsersOptions.get(), { const users = Users.find(this.findUsersOptions.get(), {
fields: { _id: true }, fields: { _id: true },
}); });
this.number.set(users.count(false)); this.numberPeople.set(users.count(false));
return users; return users;
}, },
orgNumber() {
return this.numberOrgs.get();
},
teamNumber() {
return this.numberTeams.get();
},
peopleNumber() { peopleNumber() {
return this.number.get(); return this.numberPeople.get();
},
switchMenu(event) {
const target = $(event.target);
if (!target.hasClass('active')) {
$('.side-menu li.active').removeClass('active');
target.parent().addClass('active');
const targetID = target.data('id');
this.orgSetting.set('org-setting' === targetID);
this.teamSetting.set('team-setting' === targetID);
this.peopleSetting.set('people-setting' === targetID);
}
}, },
}).register('people'); }).register('people');
Template.orgRow.helpers({
orgData() {
const orgCollection = this.esSearch ? ESSearchResults : Org;
return orgCollection.findOne(this.orgId);
},
});
Template.teamRow.helpers({
teamData() {
const teamCollection = this.esSearch ? ESSearchResults : Team;
return teamCollection.findOne(this.teamId);
},
});
Template.peopleRow.helpers({ Template.peopleRow.helpers({
userData() { userData() {
const userCollection = this.esSearch ? ESSearchResults : Users; const userCollection = this.esSearch ? ESSearchResults : Users;
@ -122,6 +222,51 @@ Template.editUserPopup.onCreated(function() {
}); });
}); });
Template.editOrgPopup.helpers({
org() {
return Org.findOne(this.orgId);
},
/*
isSelected(match) {
const orgId = Template.instance().data.orgId;
const selected = Org.findOne(orgId).authenticationMethod;
return selected === match;
},
isLdap() {
const userId = Template.instance().data.userId;
const selected = Users.findOne(userId).authenticationMethod;
return selected === 'ldap';
},
*/
errorMessage() {
return Template.instance().errorMessage.get();
},
});
Template.editTeamPopup.helpers({
team() {
return Team.findOne(this.teamId);
},
/*
authentications() {
return Template.instance().authenticationMethods.get();
},
isSelected(match) {
const userId = Template.instance().data.userId;
const selected = Users.findOne(userId).authenticationMethod;
return selected === match;
},
isLdap() {
const userId = Template.instance().data.userId;
const selected = Users.findOne(userId).authenticationMethod;
return selected === 'ldap';
},
*/
errorMessage() {
return Template.instance().errorMessage.get();
},
});
Template.editUserPopup.helpers({ Template.editUserPopup.helpers({
user() { user() {
return Users.findOne(this.userId); return Users.findOne(this.userId);
@ -144,6 +289,46 @@ Template.editUserPopup.helpers({
}, },
}); });
Template.newOrgPopup.onCreated(function() {
//this.authenticationMethods = new ReactiveVar([]);
this.errorMessage = new ReactiveVar('');
/*
Meteor.call('getAuthenticationsEnabled', (_, result) => {
if (result) {
// TODO : add a management of different languages
// (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
this.authenticationMethods.set([
{ value: 'password' },
// Gets only the authentication methods availables
...Object.entries(result)
.filter(e => e[1])
.map(e => ({ value: e[0] })),
]);
}
});
*/
});
Template.newTeamPopup.onCreated(function() {
//this.authenticationMethods = new ReactiveVar([]);
this.errorMessage = new ReactiveVar('');
/*
Meteor.call('getAuthenticationsEnabled', (_, result) => {
if (result) {
// TODO : add a management of different languages
// (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
this.authenticationMethods.set([
{ value: 'password' },
// Gets only the authentication methods availables
...Object.entries(result)
.filter(e => e[1])
.map(e => ({ value: e[0] })),
]);
}
});
*/
});
Template.newUserPopup.onCreated(function() { Template.newUserPopup.onCreated(function() {
this.authenticationMethods = new ReactiveVar([]); this.authenticationMethods = new ReactiveVar([]);
this.errorMessage = new ReactiveVar(''); this.errorMessage = new ReactiveVar('');

View file

@ -21,7 +21,7 @@ table
.ext-box-left .ext-box-left
display: flex; display: flex;
width: 40% width: 100%
span span
vertical-align: center; vertical-align: center;
@ -47,5 +47,5 @@ table
div div
margin: auto margin: auto
.more-settings-user .more-settings-user,.more-settings-team,.more-settings-org
margin-left: 10px; margin-left: 10px;

View file

@ -774,6 +774,8 @@
"display-authentication-method": "Display Authentication Method", "display-authentication-method": "Display Authentication Method",
"default-authentication-method": "Default Authentication Method", "default-authentication-method": "Default Authentication Method",
"duplicate-board": "Duplicate Board", "duplicate-board": "Duplicate Board",
"org-number": "The number of organizations is: ",
"team-number": "The number of teams is: ",
"people-number": "The number of people is: ", "people-number": "The number of people is: ",
"swimlaneDeletePopup-title": "Delete Swimlane ?", "swimlaneDeletePopup-title": "Delete Swimlane ?",
"swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.", "swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.",
@ -836,5 +838,11 @@
"hide-checked-items": "Hide checked items", "hide-checked-items": "Hide checked items",
"task": "Task", "task": "Task",
"create-task": "Create Task", "create-task": "Create Task",
"ok": "OK" "ok": "OK",
"organizations": "Organizations",
"teams": "Teams",
"displayName": "Display Name",
"shortName": "Short Name",
"website": "Website",
"person": "Person"
} }

View file

@ -1,7 +1,7 @@
Org = new Mongo.Collection('org'); Org = new Mongo.Collection('org');
/** /**
* A Organization in wekan * A Organization in Wekan. A Enterprise in Trello.
*/ */
Org.attachSchema( Org.attachSchema(
new SimpleSchema({ new SimpleSchema({
@ -18,76 +18,96 @@ Org.attachSchema(
} }
}, },
}, },
version: { displayName: {
/** /**
* the version of the organization * the name to display for the organization
*/ */
type: Number, type: String,
optional: true, optional: true,
}, },
name: { desc: {
/** /**
* name of the organization * the description the organization
*/ */
type: String, type: String,
optional: true, optional: true,
max: 190, max: 190,
}, },
address1: { name: {
/** /**
* address1 of the organization * short name of the organization
*/ */
type: String, type: String,
optional: true, optional: true,
max: 255, max: 255,
}, },
address2: { website: {
/** /**
* address2 of the organization * website of the organization
*/ */
type: String, type: String,
optional: true, optional: true,
max: 255, max: 255,
}, },
city: { teams: {
/** /**
* city of the organization * List of teams of a organization
*/ */
type: String, type: [Object],
optional: true, // eslint-disable-next-line consistent-return
max: 255, autoValue() {
if (this.isInsert && !this.isSet) {
return [
{
teamId: this.teamId,
isAdmin: true,
isActive: true,
isNoComments: false,
isCommentOnly: false,
isWorker: false,
},
];
}
},
}, },
state: { 'teams.$.teamId': {
/** /**
* state of the organization * The uniq ID of the team
*/ */
type: String, type: String,
optional: true,
max: 255,
}, },
zipCode: { 'teams.$.isAdmin': {
/** /**
* zipCode of the organization * Is the team an admin of the board?
*/ */
type: String, type: Boolean,
optional: true,
max: 50,
}, },
country: { 'teams.$.isActive': {
/** /**
* country of the organization * Is the team active?
*/ */
type: String, type: Boolean,
optional: true,
max: 255,
}, },
billingEmail: { 'teams.$.isNoComments': {
/** /**
* billingEmail of the organization * Is the team not allowed to make comments
*/ */
type: String, type: Boolean,
optional: true,
},
'teams.$.isCommentOnly': {
/**
* Is the team only allowed to comment on the board
*/
type: Boolean,
optional: true,
},
'teams.$.isWorker': {
/**
* Is the team only allowed to move card, assign himself to card and comment
*/
type: Boolean,
optional: true, optional: true,
max: 255,
}, },
createdAt: { createdAt: {
/** /**

90
models/team.js Normal file
View file

@ -0,0 +1,90 @@
Team = new Mongo.Collection('team');
/**
* A Team in Wekan. Organization in Trello.
*/
Team.attachSchema(
new SimpleSchema({
_id: {
/**
* the organization id
*/
type: Number,
optional: true,
// eslint-disable-next-line consistent-return
autoValue() {
if (this.isInsert && !this.isSet) {
return incrementCounter('counters', 'orgId', 1);
}
},
},
displayName: {
/**
* the name to display for the team
*/
type: String,
optional: true,
},
desc: {
/**
* the description the team
*/
type: String,
optional: true,
max: 190,
},
name: {
/**
* short name of the team
*/
type: String,
optional: true,
max: 255,
},
website: {
/**
* website of the team
*/
type: String,
optional: true,
max: 255,
},
createdAt: {
/**
* creation date of the team
*/
type: Date,
// eslint-disable-next-line consistent-return
autoValue() {
if (this.isInsert) {
return new Date();
} else if (this.isUpsert) {
return { $setOnInsert: new Date() };
} else {
this.unset();
}
},
},
modifiedAt: {
type: Date,
denyUpdate: false,
// eslint-disable-next-line consistent-return
autoValue() {
if (this.isInsert || this.isUpsert || this.isUpdate) {
return new Date();
} else {
this.unset();
}
},
},
}),
);
if (Meteor.isServer) {
// Index for Team name.
Meteor.startup(() => {
Team._collection._ensureIndex({ name: -1 });
});
}
export default Team;

View file

@ -0,0 +1,27 @@
Meteor.publish('org', function(query, limit) {
check(query, Match.OneOf(Object, null));
check(limit, Number);
if (!Match.test(this.userId, String)) {
return [];
}
const user = Users.findOne(this.userId);
if (user && user.isAdmin) {
return Org.find(query, {
limit,
sort: { createdAt: -1 },
fields: {
displayName: 1,
desc: 1,
name: 1,
website: 1,
teams: 1,
createdAt: 1,
loginDisabled: 1,
},
});
}
return [];
});

View file

@ -0,0 +1,27 @@
Meteor.publish('team', function(query, limit) {
check(query, Match.OneOf(Object, null));
check(limit, Number);
if (!Match.test(this.userId, String)) {
return [];
}
const user = Users.findOne(this.userId);
if (user && user.isAdmin) {
return Team.find(query, {
limit,
sort: { createdAt: -1 },
fields: {
displayName: 1,
desc: 1,
name: 1,
website: 1,
teams: 1,
createdAt: 1,
loginDisabled: 1,
},
});
}
return [];
});