From d05bf17e00a2a219b3e6f1aaf70ba7efeff43d28 Mon Sep 17 00:00:00 2001 From: Tom Watson Date: Mon, 31 Oct 2022 14:32:01 -0700 Subject: [PATCH 01/10] Add default general topic to all new groups --- api/models/Group.js | 13 +++++++++++-- migrations/schema.sql | 7 +++++++ test/unit/models/GroupExtension.test.js | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/api/models/Group.js b/api/models/Group.js index 1221ac8c1..7b91f964f 100644 --- a/api/models/Group.js +++ b/api/models/Group.js @@ -318,6 +318,13 @@ module.exports = bookshelf.Model.extend(merge({ return updatedMemberships.concat(newMemberships) }, + createDefaultTopics: async function (group_id, user_id, transacting) { + return Tag.where({ name: 'general' }).fetch({ transacting }) + .then(generalTag => { + return GroupTag.create({ updated_at: new Date(), group_id, tag_id: generalTag.get('id'), user_id, is_default: true }, { transacting }) + }) + }, + createInitialWidgets: async function (transacting) { // In the future this will have to look up the template of whatever group is being created and add widgets based on that const initialWidgets = await Widget.query(q => q.whereIn('id', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 19, 20, 21])).fetchAll({ transacting }) @@ -553,7 +560,7 @@ module.exports = bookshelf.Model.extend(merge({ })) const memberships = await bookshelf.transaction(async trx => { - await group.save(null, {transacting: trx}) + await group.save(null, { transacting: trx }) if (data.group_extensions) { for (const extData of data.group_extensions) { @@ -570,9 +577,11 @@ module.exports = bookshelf.Model.extend(merge({ await group.createStarterPosts(trx) await group.createInitialWidgets(trx) + + await group.createDefaultTopics(group.id, userId, trx) const members = await group.addMembers([userId], - {role: GroupMembership.Role.MODERATOR}, { transacting: trx }) + { role: GroupMembership.Role.MODERATOR }, { transacting: trx }) // Have to add/request add to parent group after moderator has been added to the group if (data.parent_ids) { diff --git a/migrations/schema.sql b/migrations/schema.sql index 287f9a65f..c6cf6c594 100644 --- a/migrations/schema.sql +++ b/migrations/schema.sql @@ -1664,6 +1664,7 @@ CREATE TABLE public.posts ( is_public boolean DEFAULT false, donations_link character varying(255), project_management_link character varying(255), + reactions_summary jsonb, link_preview_featured boolean DEFAULT false ); @@ -5046,6 +5047,12 @@ ALTER TABLE ONLY public.users ADD CONSTRAINT users_stripe_account_id_foreign FOREIGN KEY (stripe_account_id) REFERENCES public.stripe_accounts(id); +-- +-- Data seeding +-- + +insert into tags (name) values ('general') ON CONFLICT DO NOTHING + -- -- PostgreSQL database dump complete -- diff --git a/test/unit/models/GroupExtension.test.js b/test/unit/models/GroupExtension.test.js index 8caf8f7fd..4b9056aa7 100644 --- a/test/unit/models/GroupExtension.test.js +++ b/test/unit/models/GroupExtension.test.js @@ -15,6 +15,7 @@ describe('GroupExtension', function () { slug: 'comm1', group_data_type: 1 } + await Tag.findOrCreate('general') user = await new User({ name: 'username', email: 'john@foo.com', active: true }).save() await Group.create(user.id, data) savedGroup = await Group.find('comm1') From f611b31ed39cc64bc2430975b452b1f967d7d48f Mon Sep 17 00:00:00 2001 From: Tom Watson Date: Tue, 1 Nov 2022 16:02:25 -0700 Subject: [PATCH 02/10] Pick settings on group creation --- api/models/Group.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/api/models/Group.js b/api/models/Group.js index 7b91f964f..afb3f586c 100644 --- a/api/models/Group.js +++ b/api/models/Group.js @@ -538,7 +538,7 @@ module.exports = bookshelf.Model.extend(merge({ pick(data, 'about_video_uri', 'accessibility', 'avatar_url', 'description', 'slug', 'category', 'access_code', 'banner_url', 'location_id', 'location', 'group_data_type', 'moderator_descriptor', - 'moderator_descriptor_plural', 'name', 'type', 'type_descriptor', 'type_descriptor_plural', 'visibility' + 'moderator_descriptor_plural', 'name', 'settings', 'type', 'type_descriptor', 'type_descriptor_plural', 'visibility' ), { 'accessibility': Group.Accessibility.RESTRICTED, @@ -551,7 +551,6 @@ module.exports = bookshelf.Model.extend(merge({ // eslint-disable-next-line camelcase const access_code = attrs.access_code || await Group.getNewAccessCode() - const group = new Group(merge(attrs, { access_code, created_at: new Date(), From 8e196a03c9008181df307b9a47db8bb1bbcaa769 Mon Sep 17 00:00:00 2001 From: Loren Johnson Date: Thu, 3 Nov 2022 11:50:18 -0700 Subject: [PATCH 03/10] Update hylo-shared. Will autolink now where shared markdown helper is used --- package.json | 2 +- yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index a69ea5217..f90f2bbfa 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "hast-util-to-string": "^1.0.1", "hastscript": "^3.1.0", "he": "^1.2.0", - "hylo-shared": "5.0.0", + "hylo-shared": "5.1.0", "image-size": "^0.3.5", "insane": "^2.6.2", "jade": "^1.11.0", diff --git a/yarn.lock b/yarn.lock index 268491619..91eb3381a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7036,15 +7036,15 @@ https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: agent-base "6" debug "4" -hylo-shared@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/hylo-shared/-/hylo-shared-5.0.0.tgz#7cc76a87d092947b9c78aafb270e059d29866e41" - integrity sha512-72wTvmE1VfZEZ6Hk6jdrmXz4ocF66Y6FkHFDjqRwO9KYe5FSRwOY9tImperx12sB8GZY+Ss1R8sn0JF8IhOyyA== +hylo-shared@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/hylo-shared/-/hylo-shared-5.1.0.tgz#e4cdb43a2d65926d195bb70e6a24b874efc03f52" + integrity sha512-YWXEs8F/Sw6yazUi6Nii8JMoLa9P5HfnUJ8B+JcyZNs3EaDbf04FVZdi1bFYMgzcl+uNNx9ebRWY+2mJPGRqoQ== dependencies: coordinate-parser "^1.0.7" html-to-text "^8.1.0" lodash "~4.17.21" - marked "^4.0.12" + marked "^4.2.1" pretty-date "^0.2.0" querystring "^0.2.1" trunc-html "^1.1.2" @@ -8645,10 +8645,10 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -marked@^4.0.12: - version "4.1.1" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.1.1.tgz#2f709a4462abf65a283f2453dc1c42ab177d302e" - integrity sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw== +marked@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.1.tgz#eaa32594e45b4e58c02e4d118531fd04345de3b4" + integrity sha512-VK1/jNtwqDLvPktNpL0Fdg3qoeUZhmRsuiIjPEy/lHwXW4ouLoZfO4XoWd4ClDt+hupV1VLpkZhEovjU0W/kqA== math-interval-parser@^2.0.1: version "2.0.1" From 1054fff7cc4f7710c61385c5961ad1d3d6b6b7f0 Mon Sep 17 00:00:00 2001 From: Loren Johnson Date: Thu, 3 Nov 2022 12:00:03 -0700 Subject: [PATCH 04/10] Maintaining legacy markdown non-autolinking behavior for untested cases --- api/controllers/CommentController.js | 2 +- api/models/Comment.js | 2 +- api/services/InvitationService.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/controllers/CommentController.js b/api/controllers/CommentController.js index 7cdf21a18..505742f11 100644 --- a/api/controllers/CommentController.js +++ b/api/controllers/CommentController.js @@ -42,7 +42,7 @@ module.exports = { // TODO: fix const { groupId, userId } = res.locals.tokenData - const replyText = postId => TextHelpers.markdown(req.param(`post-${postId}`)) + const replyText = postId => TextHelpers.markdown(req.param(`post-${postId}`, { disableAutolinking: true })) const postIds = flow( Object.keys, diff --git a/api/models/Comment.js b/api/models/Comment.js index 3e735ce6d..5ba1fc39a 100644 --- a/api/models/Comment.js +++ b/api/models/Comment.js @@ -138,7 +138,7 @@ module.exports = bookshelf.Model.extend(Object.assign({ }) const finalText = cutoff ? lines.slice(0, cutoff).join('\n') : text - return opts.useMarkdown ? TextHelpers.markdown(finalText || '') : finalText + return opts.useMarkdown ? TextHelpers.markdown(finalText || '', { disableAutolinking: true }) : finalText }, notifyAboutMessage, diff --git a/api/services/InvitationService.js b/api/services/InvitationService.js index 6d1fc8e5e..4df6f2fb8 100644 --- a/api/services/InvitationService.js +++ b/api/services/InvitationService.js @@ -90,7 +90,7 @@ module.exports = { if (tag) { opts.tagId = tag.id } else { - opts.message = TextHelpers.markdown(message) + opts.message = TextHelpers.markdown(message, { disableAutolinking: true }) opts.moderator = isModerator opts.subject = subject } From 76a300970abe07afc94e8f04865755077c33c443 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Thu, 10 Nov 2022 22:43:23 -0800 Subject: [PATCH 05/10] Add allow_in_public column to groups When off then people are not allowed to create public posts from that group. Meaning a post that is chosen to be public must also be posted in at least one group that has allow_in_public set to true. Fixes https://github.com/Hylozoic/hylo-node/issues/889 --- api/graphql/filters.js | 10 +++++-- api/models/post/createPost.js | 28 +++++++++++-------- api/models/post/setupPostAttrs.js | 1 - ...110125837_show-in-public-flag-to-groups.js | 11 ++++++++ 4 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 migrations/20221110125837_show-in-public-flag-to-groups.js diff --git a/api/graphql/filters.js b/api/graphql/filters.js index 1f30f788c..4d9408d5f 100644 --- a/api/graphql/filters.js +++ b/api/graphql/filters.js @@ -25,6 +25,8 @@ export const groupFilter = userId => relation => { // non authenticated queries can only see public groups if (!userId) { q.where('groups.visibility', Group.Visibility.PUBLIC) + // Only show groups that are allowed to be show in public + q.andWhere('allow_in_public', true) } else { // the effect of using `where` like this is to wrap everything within its // callback in parentheses -- this is necessary to keep `or` from "leaking" @@ -38,7 +40,7 @@ export const groupFilter = userId => relation => { // Can see groups you are a member of... q2.whereIn('groups.id', selectIdsForMember) - // + their parent group + // + their parent groups q2.orWhereIn('groups.id', parentGroupIds) // + child groups that are not hidden, except moderators of a group can see its hidden children q2.orWhere(q3 => { @@ -49,7 +51,11 @@ export const groupFilter = userId => relation => { q3.orWhereIn('groups.id', childrenOfModeratedGroupIds) }) // + all public groups - q2.orWhere('groups.visibility', Group.Visibility.PUBLIC) + q2.orWhere(q5 => { + q5.where('groups.visibility', Group.Visibility.PUBLIC) + // Only show groups that are allowed to be show in public + q5.andWhere('allow_in_public', true) + }) }) } }) diff --git a/api/models/post/createPost.js b/api/models/post/createPost.js index 82b158825..33607f21b 100644 --- a/api/models/post/createPost.js +++ b/api/models/post/createPost.js @@ -3,18 +3,24 @@ import setupPostAttrs from './setupPostAttrs' import updateChildren from './updateChildren' import { groupRoom, pushToSockets } from '../../services/Websockets' -export default function createPost (userId, params) { +export default async function createPost (userId, params) { + if (params.isPublic) { + const groups = await Group.query(q => q.whereIn('id', params.group_ids)).fetchAll() + const allowedToMakePublic = groups.find(g => g.get('allow_in_public')) + if (!allowedToMakePublic) params.isPublic = false + } + return setupPostAttrs(userId, merge(Post.newPostAttrs(), params)) - .then(attrs => bookshelf.transaction(transacting => - Post.create(attrs, { transacting }) - .tap(post => afterCreatingPost(post, merge( - pick(params, 'group_ids', 'imageUrl', 'videoUrl', 'docs', 'topicNames', 'memberIds', 'eventInviteeIds', 'imageUrls', 'fileUrls', 'announcement', 'location', 'location_id'), - {children: params.requests, transacting} - )))).then(function(inserts) { - return inserts - }).catch(function(error) { - throw error - }) + .then(attrs => bookshelf.transaction(transacting => + Post.create(attrs, { transacting }) + .tap(post => afterCreatingPost(post, merge( + pick(params, 'group_ids', 'imageUrl', 'videoUrl', 'docs', 'topicNames', 'memberIds', 'eventInviteeIds', 'imageUrls', 'fileUrls', 'announcement', 'location', 'location_id'), + {children: params.requests, transacting} + )))).then(function(inserts) { + return inserts + }).catch(function(error) { + throw error + }) ) } diff --git a/api/models/post/setupPostAttrs.js b/api/models/post/setupPostAttrs.js index 1270d91a8..e5eee1fb3 100644 --- a/api/models/post/setupPostAttrs.js +++ b/api/models/post/setupPostAttrs.js @@ -4,7 +4,6 @@ import { getOr } from 'lodash/fp' export default function setupPostAttrs (userId, params) { const attrs = merge({ user_id: userId, - visibility: params.public ? Post.Visibility.PUBLIC_READABLE : Post.Visibility.DEFAULT, link_preview_id: params.link_preview_id || getOr(null, 'id', params.linkPreview), parent_post_id: params.parent_post_id, updated_at: new Date(), diff --git a/migrations/20221110125837_show-in-public-flag-to-groups.js b/migrations/20221110125837_show-in-public-flag-to-groups.js new file mode 100644 index 000000000..45d4d1f2c --- /dev/null +++ b/migrations/20221110125837_show-in-public-flag-to-groups.js @@ -0,0 +1,11 @@ +exports.up = function (knex) { + return knex.schema.table('groups', table => { + table.boolean('allow_in_public').defaultTo(false) + }) +} + +exports.down = function (knex) { + return knex.schema.table('groups', table => { + table.dropColumn('allow_in_public') + }) +} From 7c297c776442e1d692e031552708918d27d1dd31 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Thu, 10 Nov 2022 22:46:15 -0800 Subject: [PATCH 06/10] Comment --- api/models/post/createPost.js | 1 + 1 file changed, 1 insertion(+) diff --git a/api/models/post/createPost.js b/api/models/post/createPost.js index 33607f21b..a2251044a 100644 --- a/api/models/post/createPost.js +++ b/api/models/post/createPost.js @@ -5,6 +5,7 @@ import { groupRoom, pushToSockets } from '../../services/Websockets' export default async function createPost (userId, params) { if (params.isPublic) { + // Don't allow creating a public post unless at least one of the post's groups has allow_in_public set to true const groups = await Group.query(q => q.whereIn('id', params.group_ids)).fetchAll() const allowedToMakePublic = groups.find(g => g.get('allow_in_public')) if (!allowedToMakePublic) params.isPublic = false From dfe315c3851be6da6af80c120004d236a7e82902 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Sun, 13 Nov 2022 11:48:58 -0800 Subject: [PATCH 07/10] Add allow_in_public to schema --- migrations/schema.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migrations/schema.sql b/migrations/schema.sql index c6cf6c594..18dcb55ca 100644 --- a/migrations/schema.sql +++ b/migrations/schema.sql @@ -1042,7 +1042,8 @@ CREATE TABLE public.groups ( type_descriptor_plural character varying(255) DEFAULT NULL::character varying, moderator_descriptor character varying(255) DEFAULT NULL::character varying, moderator_descriptor_plural character varying(255) DEFAULT NULL::character varying, - about_video_uri character varying(255) + about_video_uri character varying(255), + allow_in_public boolean DEFAULT false ); From 9369452e77bc94bfa2f7766d13e7397645fc91cb Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Sun, 13 Nov 2022 13:42:13 -0800 Subject: [PATCH 08/10] Farm groups by default are allowed in public --- api/models/Group.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/api/models/Group.js b/api/models/Group.js index afb3f586c..bf8b0f175 100644 --- a/api/models/Group.js +++ b/api/models/Group.js @@ -534,7 +534,7 @@ module.exports = bookshelf.Model.extend(merge({ throw new GraphQLYogaError("A group with that URL slug already exists") } - var attrs = defaults( + let attrs = defaults( pick(data, 'about_video_uri', 'accessibility', 'avatar_url', 'description', 'slug', 'category', 'access_code', 'banner_url', 'location_id', 'location', 'group_data_type', 'moderator_descriptor', @@ -549,6 +549,11 @@ module.exports = bookshelf.Model.extend(merge({ } ) + // XXX: temporary, by default show all farms in public. These can only be created via API right now + if (attrs.type === 'farm') { + attrs.allow_in_public = true + } + // eslint-disable-next-line camelcase const access_code = attrs.access_code || await Group.getNewAccessCode() const group = new Group(merge(attrs, { From 689d21ab5d3cc4d4fde387a8bdd79e30e8b39629 Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Sun, 13 Nov 2022 14:08:23 -0800 Subject: [PATCH 09/10] Fix test --- api/controllers/PostController.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/api/controllers/PostController.js b/api/controllers/PostController.js index 58c00d458..7ac12da81 100644 --- a/api/controllers/PostController.js +++ b/api/controllers/PostController.js @@ -44,11 +44,14 @@ const PostController = { } })) .then(stop => stop || createPost(userId, attributes) - .tap(() => Analytics.track({ - userId, - event: 'Add Post by Email Form', - properties: {group: group.get('name')} - })) + .then(post => { + Analytics.track({ + userId, + event: 'Add Post by Email Form', + properties: {group: group.get('name')} + }) + return post + }) .then(post => res.redirect(Frontend.Route.post(post, group)))) .catch(res.serverError) }, From a94f687f66423ac5188c212b29541f8bd89d62ed Mon Sep 17 00:00:00 2001 From: Tibet Sprague Date: Sun, 13 Nov 2022 14:21:14 -0800 Subject: [PATCH 10/10] Update CHANGELOG and version to 5.0.2 --- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0264b1af8..aeee9f039 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [5.0.2] - 2022-11-13 + +### Added +- New allow_in_public flag on groups that determines whether the group appears in the Group Explorer and whether posts from that group are allowed in the public stream. This flag is turned off for new groups by default while we figure out our strategy for deciding whether it should be on or off for any given group. +- Every new group has a #general topic added to it as a default topic. This will be more important/useful when topic based chat rooms are released soon! + +### Fixed +- Update `hylo-shared` to fix bug in Mention HTMl generation +- Autolinking (links being turned into clickable links) in Group descriptions is turned back on +- Can set group settings when creating a group via API. This fixes an issue where the group's locationDisplayPrecision was not being set correctly. + ## [5.0.1] - 2022-10-24 ### Fixed diff --git a/package.json b/package.json index f90f2bbfa..12eec70b8 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Tibet Sprague ", "license": "GNU AFFERO GENERAL PUBLIC LICENSE v3", "private": true, - "version": "5.0.1", + "version": "5.0.2", "repository": { "type": "git", "url": "git://github.com/Hylozoic/hylo-node.git"