From 30fc61dbc6939f8f02224c2ce1184b0d99053d51 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Tue, 28 Jul 2020 23:14:41 -0700 Subject: [PATCH] Add community_templates with associated default topics Let communities be created with a template and default topics associated --- api/graphql/index.js | 1 + api/graphql/makeModels.js | 13 +++++++ api/graphql/schema.graphql | 16 +++++++++ api/models/Community.js | 14 +++++++- api/models/CommunityTemplate.js | 18 ++++++++++ api/models/Tag.js | 4 +++ ...722214505_add_community_templates_table.js | 36 +++++++++++++++++++ package.json | 1 + 8 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 api/models/CommunityTemplate.js create mode 100644 migrations/20200722214505_add_community_templates_table.js diff --git a/api/graphql/index.js b/api/graphql/index.js index 7f49a24af..536f56173 100644 --- a/api/graphql/index.js +++ b/api/graphql/index.js @@ -136,6 +136,7 @@ export function makeQueries (userId, fetchOne, fetchMany) { throw new Error('Slug is invalid') }, communities: (root, args) => fetchMany('Community', args), + communityTemplates: (root, args) => CommunityTemplate.fetchAll(), notifications: (root, { first, offset, resetCount, order = 'desc' }) => { return fetchMany('Notification', { first, offset, order }) .tap(() => resetCount && User.resetNewNotificationCount(userId)) diff --git a/api/graphql/makeModels.js b/api/graphql/makeModels.js index cdf937a04..8984673af 100644 --- a/api/graphql/makeModels.js +++ b/api/graphql/makeModels.js @@ -270,6 +270,19 @@ export default async function makeModels (userId, isAdmin) { }) }, + CommunityTemplate: { + model: CommunityTemplate, + attributes: [ + 'name', + 'display_name' + ], + relations: [ + 'communities', + 'defaultTopics' + ], + fetchMany: () => CommunityTemplate + }, + Invitation: { model: Invitation, attributes: [ diff --git a/api/graphql/schema.graphql b/api/graphql/schema.graphql index 83cfe18b7..1d1e6f2a3 100644 --- a/api/graphql/schema.graphql +++ b/api/graphql/schema.graphql @@ -42,6 +42,19 @@ type UserSettings { lastViewedMessagesAt: String } +type CommunityTemplate { + id: ID + name: String + displayName: String + communities: CommunityQuerySet + communitiesTotal: Int + defaultTopics: [Topic] + defaultTopicsTotal: Int + newPostCount: Int + updatedAt: String + createdAt: String +} + type CommunityTopicQuerySet { total: Int hasMore: Boolean @@ -437,6 +450,7 @@ type Query { boundingBox: [PointInput], isPublic: Boolean ): CommunityQuerySet + communityTemplates: [CommunityTemplate] messageThread(id: ID): MessageThread post(id: ID): Post posts( @@ -610,6 +624,7 @@ input InviteInput { } input CommunityInput { + communityTemplateId: ID name: String slug: String description: String @@ -627,6 +642,7 @@ input CommunityInput { isPublic: Boolean isAutoJoinable: Boolean publicMemberDirectory: Boolean + defaultTopics: [String] } input CommunitySettingsInput { diff --git a/api/models/Community.js b/api/models/Community.js index 059852896..713f1657d 100644 --- a/api/models/Community.js +++ b/api/models/Community.js @@ -303,7 +303,7 @@ module.exports = bookshelf.Model.extend(merge({ async create (userId, data) { var attrs = defaults( pick(data, - 'name', 'description', 'slug', 'category', + 'name', 'description', 'slug', 'category', 'community_template_id', 'beta_access_code', 'banner_url', 'avatar_url', 'location_id', 'location', 'network_id'), {'banner_url': DEFAULT_BANNER, 'avatar_url': DEFAULT_AVATAR}) @@ -321,6 +321,18 @@ module.exports = bookshelf.Model.extend(merge({ const memberships = await bookshelf.transaction(async trx => { await community.save(null, {transacting: trx}) await community.createStarterPosts(trx) + if (data.default_topics) { + data.default_topics.forEach(async name => { + const topic = await Tag.findOrCreate(name, {transacting: trx}) + await Tag.addToCommunity({ + community_id: community.id, + tag_id: topic.id, + user_id: userId, + is_default: true, + isSubscribing: true + }, {transacting: trx}) + }) + } return community.addGroupMembers([userId], {role: GroupMembership.Role.MODERATOR}, {transacting: trx}) }) diff --git a/api/models/CommunityTemplate.js b/api/models/CommunityTemplate.js new file mode 100644 index 000000000..6abf7ae53 --- /dev/null +++ b/api/models/CommunityTemplate.js @@ -0,0 +1,18 @@ +import { includes } from 'lodash' + +var knex = bookshelf.knex + +module.exports = bookshelf.Model.extend({ + tableName: 'community_templates', + + communities: function () { + return this.hasMany(Community).query({where: {'communities.active': true}}) + }, + + defaultTopics: function () { + return this.belongsToMany(Tag, 'community_template_default_topics', 'community_template_id', 'tag_id') + }, + +}, { + +}) diff --git a/api/models/Tag.js b/api/models/Tag.js index 5394b54c7..a42be97ec 100644 --- a/api/models/Tag.js +++ b/api/models/Tag.js @@ -83,6 +83,10 @@ module.exports = bookshelf.Model.extend({ .withPivot(['user_id', 'description']) }, + communityTemplates: function () { + return this.belongsToMany(CommunityTemplate, 'blocked_users', 'tag_id', 'community_template_id') + }, + communityTags: function () { return this.hasMany(CommunityTag) }, diff --git a/migrations/20200722214505_add_community_templates_table.js b/migrations/20200722214505_add_community_templates_table.js new file mode 100644 index 000000000..2776dd950 --- /dev/null +++ b/migrations/20200722214505_add_community_templates_table.js @@ -0,0 +1,36 @@ +exports.up = async function(knex, Promise) { + await knex.schema.createTable('community_templates', table => { + table.increments().primary() + + table.string('name') + table.string('display_name') + table.index(['name']) + + table.timestamp('created_at') + table.timestamp('updated_at') + }) + + await knex.schema.createTable('community_template_default_topics', table => { + table.increments().primary() + + table.bigInteger('community_template_id').references('id').inTable('community_templates') + table.bigInteger('tag_id').references('id').inTable('tags') + table.index(['community_template_id']) + + table.timestamp('created_at') + table.timestamp('updated_at') + }) + + return knex.schema.table('communities', table => { + table.bigInteger('community_template_id').references('id').inTable('community_templates') + }) +}; + +exports.down = async function(knex, Promise) { + await knex.schema.dropTable('community_templates') + await knex.schema.dropTable('community_template_default_topics') + + return knex.schema.table('communities', table => { + table.dropColumn('community_template_id') + }) +}; \ No newline at end of file diff --git a/package.json b/package.json index a24b90cb5..641de91f9 100644 --- a/package.json +++ b/package.json @@ -166,6 +166,7 @@ "CommentTag", "Community", "CommunityTag", + "CommunityTemplate", "Contribution", "Device", "Email",