mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
commit
4247835dc5
11 changed files with 171 additions and 22 deletions
|
|
@ -187,14 +187,23 @@ const appendIdsFilter = (body: SearchBody, ids: string[]): void => {
|
|||
}
|
||||
|
||||
const appendRecommendedBy = (body: SearchBody, recommendedBy: string): void => {
|
||||
const query =
|
||||
recommendedBy === '*'
|
||||
? {
|
||||
exists: {
|
||||
field: 'recommendations',
|
||||
},
|
||||
}
|
||||
: {
|
||||
term: {
|
||||
'recommendations.name': recommendedBy,
|
||||
},
|
||||
}
|
||||
|
||||
body.query.bool.must.push({
|
||||
nested: {
|
||||
path: 'recommendations',
|
||||
query: {
|
||||
term: {
|
||||
'recommendations.name': recommendedBy,
|
||||
},
|
||||
},
|
||||
query,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
import { Page, PageContext, Recommendation } from './types'
|
||||
import {
|
||||
ArticleSavingRequestStatus,
|
||||
Page,
|
||||
PageContext,
|
||||
Recommendation,
|
||||
} from './types'
|
||||
import { createPage, getPageByParam, updatePage } from './pages'
|
||||
|
||||
export const addRecommendation = async (
|
||||
|
|
@ -66,7 +71,14 @@ export const addRecommendation = async (
|
|||
sharedAt: new Date(),
|
||||
highlights,
|
||||
readAt: undefined,
|
||||
labels: [],
|
||||
labels: undefined,
|
||||
subscription: undefined,
|
||||
unsubHttpUrl: undefined,
|
||||
unsubMailTo: undefined,
|
||||
_id: undefined,
|
||||
archivedAt: undefined,
|
||||
state: ArticleSavingRequestStatus.Succeeded,
|
||||
taskName: undefined,
|
||||
}
|
||||
|
||||
return createPage(newPage, ctx)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,10 @@ export interface SearchBody {
|
|||
nested: {
|
||||
path: 'recommendations'
|
||||
query: {
|
||||
term: {
|
||||
exists?: {
|
||||
field: string
|
||||
}
|
||||
term?: {
|
||||
'recommendations.name': string
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,4 +32,16 @@ export class Group {
|
|||
|
||||
@OneToMany(() => GroupMembership, (groupMembership) => groupMembership.group)
|
||||
members!: GroupMembership[]
|
||||
|
||||
@Column('text', { nullable: true })
|
||||
description?: string | null
|
||||
|
||||
@Column('text', { nullable: true })
|
||||
topics?: string | null
|
||||
|
||||
@Column('boolean', { default: false })
|
||||
onlyAdminCanPost!: boolean
|
||||
|
||||
@Column('boolean', { default: false })
|
||||
onlyAdminCanSeeMembers!: boolean
|
||||
}
|
||||
|
|
|
|||
|
|
@ -287,9 +287,13 @@ export enum CreateGroupErrorCode {
|
|||
}
|
||||
|
||||
export type CreateGroupInput = {
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
expiresInDays?: InputMaybe<Scalars['Int']>;
|
||||
maxMembers?: InputMaybe<Scalars['Int']>;
|
||||
name: Scalars['String'];
|
||||
onlyAdminCanPost?: InputMaybe<Scalars['Boolean']>;
|
||||
onlyAdminCanSeeMembers?: InputMaybe<Scalars['Boolean']>;
|
||||
topics?: InputMaybe<Array<Scalars['String']>>;
|
||||
};
|
||||
|
||||
export type CreateGroupResult = CreateGroupError | CreateGroupSuccess;
|
||||
|
|
@ -1866,11 +1870,15 @@ export type Recommendation = {
|
|||
export type RecommendationGroup = {
|
||||
__typename?: 'RecommendationGroup';
|
||||
admins: Array<User>;
|
||||
canPost: Scalars['Boolean'];
|
||||
canSeeMembers: Scalars['Boolean'];
|
||||
createdAt: Scalars['Date'];
|
||||
description?: Maybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
inviteUrl: Scalars['String'];
|
||||
members: Array<User>;
|
||||
name: Scalars['String'];
|
||||
topics?: Maybe<Array<Scalars['String']>>;
|
||||
updatedAt: Scalars['Date'];
|
||||
};
|
||||
|
||||
|
|
@ -4959,11 +4967,15 @@ export type RecommendationResolvers<ContextType = ResolverContext, ParentType ex
|
|||
|
||||
export type RecommendationGroupResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['RecommendationGroup'] = ResolversParentTypes['RecommendationGroup']> = {
|
||||
admins?: Resolver<Array<ResolversTypes['User']>, ParentType, ContextType>;
|
||||
canPost?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
canSeeMembers?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
createdAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
|
||||
description?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
|
||||
inviteUrl?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
members?: Resolver<Array<ResolversTypes['User']>, ParentType, ContextType>;
|
||||
name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
topics?: Resolver<Maybe<Array<ResolversTypes['String']>>, ParentType, ContextType>;
|
||||
updatedAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -243,9 +243,13 @@ enum CreateGroupErrorCode {
|
|||
}
|
||||
|
||||
input CreateGroupInput {
|
||||
description: String
|
||||
expiresInDays: Int
|
||||
maxMembers: Int
|
||||
name: String!
|
||||
onlyAdminCanPost: Boolean
|
||||
onlyAdminCanSeeMembers: Boolean
|
||||
topics: [String!]
|
||||
}
|
||||
|
||||
union CreateGroupResult = CreateGroupError | CreateGroupSuccess
|
||||
|
|
@ -1312,11 +1316,15 @@ type Recommendation {
|
|||
|
||||
type RecommendationGroup {
|
||||
admins: [User!]!
|
||||
canPost: Boolean!
|
||||
canSeeMembers: Boolean!
|
||||
createdAt: Date!
|
||||
description: String
|
||||
id: ID!
|
||||
inviteUrl: String!
|
||||
members: [User!]!
|
||||
name: String!
|
||||
topics: [String!]
|
||||
updatedAt: Date!
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import { In } from 'typeorm'
|
|||
import { getPageByParam } from '../../elastic/pages'
|
||||
import { enqueueRecommendation } from '../../utils/createTask'
|
||||
import { env } from '../../env'
|
||||
import { analytics } from '../../utils/analytics'
|
||||
|
||||
export const createGroupResolver = authorized<
|
||||
CreateGroupSuccess,
|
||||
|
|
@ -70,6 +71,20 @@ export const createGroupResolver = authorized<
|
|||
name: input.name,
|
||||
maxMembers: input.maxMembers,
|
||||
expiresInDays: input.expiresInDays,
|
||||
description: input.description,
|
||||
topics: input.topics,
|
||||
onlyAdminCanPost: input.onlyAdminCanPost,
|
||||
onlyAdminCanSeeMembers: input.onlyAdminCanSeeMembers,
|
||||
})
|
||||
|
||||
analytics.track({
|
||||
userId: uid,
|
||||
event: 'group_created',
|
||||
properties: {
|
||||
group_id: group.id,
|
||||
group_name: group.name,
|
||||
group_invite_code: invite.code,
|
||||
},
|
||||
})
|
||||
|
||||
await createLabelAndRuleForGroup(uid, group.name)
|
||||
|
|
@ -83,6 +98,10 @@ export const createGroupResolver = authorized<
|
|||
inviteUrl,
|
||||
admins: [user],
|
||||
members: [user],
|
||||
canSeeMembers: true,
|
||||
canPost: true,
|
||||
description: group.description,
|
||||
topics: group.topics?.split(','),
|
||||
},
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -264,6 +283,15 @@ export const joinGroupResolver = authorized<
|
|||
|
||||
const group = await joinGroup(user, inviteCode)
|
||||
|
||||
analytics.track({
|
||||
userId: uid,
|
||||
event: 'group_joined',
|
||||
properties: {
|
||||
group_id: group.id,
|
||||
group_name: group.name,
|
||||
},
|
||||
})
|
||||
|
||||
await createLabelAndRuleForGroup(user.id, group.name)
|
||||
|
||||
return {
|
||||
|
|
@ -403,6 +431,14 @@ export const leaveGroupResolver = authorized<
|
|||
|
||||
const success = await leaveGroup(user, groupId)
|
||||
|
||||
analytics.track({
|
||||
userId: uid,
|
||||
event: 'group_left',
|
||||
properties: {
|
||||
group_id: groupId,
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
success,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2158,6 +2158,10 @@ const schema = gql`
|
|||
name: String! @sanitize(maxLength: 140)
|
||||
maxMembers: Int
|
||||
expiresInDays: Int
|
||||
description: String
|
||||
topics: [String!]
|
||||
onlyAdminCanPost: Boolean
|
||||
onlyAdminCanSeeMembers: Boolean
|
||||
}
|
||||
|
||||
union CreateGroupResult = CreateGroupSuccess | CreateGroupError
|
||||
|
|
@ -2174,6 +2178,10 @@ const schema = gql`
|
|||
members: [User!]!
|
||||
createdAt: Date!
|
||||
updatedAt: Date!
|
||||
canPost: Boolean!
|
||||
description: String
|
||||
topics: [String!]
|
||||
canSeeMembers: Boolean!
|
||||
}
|
||||
|
||||
type CreateGroupError {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ export const createGroup = async (input: {
|
|||
name: string
|
||||
maxMembers?: number | null
|
||||
expiresInDays?: number | null
|
||||
description?: string | null
|
||||
topics?: string[] | null
|
||||
onlyAdminCanPost?: boolean | null
|
||||
onlyAdminCanSeeMembers?: boolean | null
|
||||
}): Promise<[Group, Invite]> => {
|
||||
const [group, invite] = await AppDataSource.transaction<[Group, Invite]>(
|
||||
async (t) => {
|
||||
|
|
@ -32,6 +36,10 @@ export const createGroup = async (input: {
|
|||
const group = await t.getRepository(Group).save({
|
||||
name: input.name,
|
||||
createdBy: input.admin,
|
||||
description: input.description,
|
||||
topics: input.topics?.join(','),
|
||||
onlyAdminCanPost: input.onlyAdminCanPost ?? false,
|
||||
onlyAdminCanSeeMembers: input.onlyAdminCanSeeMembers ?? false,
|
||||
})
|
||||
|
||||
const code = nanoid(8)
|
||||
|
|
@ -71,13 +79,17 @@ export const getRecommendationGroups = async (
|
|||
return groupMembers.map((gm) => {
|
||||
const admins: GraphqlUser[] = []
|
||||
const members: GraphqlUser[] = []
|
||||
gm.group.members.forEach((m) => {
|
||||
const user = userDataToUser(m.user)
|
||||
if (m.isAdmin) {
|
||||
admins.push(user)
|
||||
}
|
||||
members.push(user)
|
||||
})
|
||||
const canSeeMembers = gm.group.onlyAdminCanSeeMembers ? gm.isAdmin : true
|
||||
if (canSeeMembers) {
|
||||
// Return all members
|
||||
gm.group.members.forEach((m) => {
|
||||
const user = userDataToUser(m.user)
|
||||
if (m.isAdmin) {
|
||||
admins.push(user)
|
||||
}
|
||||
members.push(user)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
id: gm.group.id,
|
||||
|
|
@ -87,6 +99,10 @@ export const getRecommendationGroups = async (
|
|||
inviteUrl: getInviteUrl(gm.invite),
|
||||
admins,
|
||||
members,
|
||||
topics: gm.group.topics?.split(','),
|
||||
description: gm.group.description,
|
||||
canPost: gm.group.onlyAdminCanPost ? gm.isAdmin : true,
|
||||
canSeeMembers,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -135,19 +151,26 @@ having count(*) < $4`,
|
|||
})
|
||||
const admins: GraphqlUser[] = []
|
||||
const members: GraphqlUser[] = []
|
||||
group.members.forEach((m) => {
|
||||
const user = userDataToUser(m.user)
|
||||
if (m.isAdmin) {
|
||||
admins.push(user)
|
||||
}
|
||||
members.push(user)
|
||||
})
|
||||
if (!group.onlyAdminCanSeeMembers) {
|
||||
// Return all members
|
||||
group.members.forEach((m) => {
|
||||
const user = userDataToUser(m.user)
|
||||
if (m.isAdmin) {
|
||||
admins.push(user)
|
||||
}
|
||||
members.push(user)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
...group,
|
||||
inviteUrl: getInviteUrl(invite),
|
||||
admins,
|
||||
members,
|
||||
topics: group.topics?.split(','),
|
||||
description: group.description,
|
||||
canPost: !group.onlyAdminCanPost,
|
||||
canSeeMembers: !group.onlyAdminCanSeeMembers,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
13
packages/db/migrations/0104.do.add_description_to_group.sql
Executable file
13
packages/db/migrations/0104.do.add_description_to_group.sql
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
-- Type: DO
|
||||
-- Name: add_description_to_group
|
||||
-- Description: Add description, topics, only_admin_can_post, only_admin_can_see_members to group table
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE omnivore."group"
|
||||
ADD COLUMN description text,
|
||||
ADD COLUMN topics text,
|
||||
ADD COLUMN only_admin_can_post boolean NOT NULL DEFAULT false,
|
||||
ADD COLUMN only_admin_can_see_members boolean NOT NULL DEFAULT false;
|
||||
|
||||
COMMIT;
|
||||
13
packages/db/migrations/0104.undo.add_description_to_group.sql
Executable file
13
packages/db/migrations/0104.undo.add_description_to_group.sql
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
-- Type: UNDO
|
||||
-- Name: add_description_to_group
|
||||
-- Description: Add description, topics, only_admin_can_post, only_admin_can_see_members to group table
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE omnivore."group"
|
||||
DROP COLUMN IF EXISTS description,
|
||||
DROP COLUMN IF EXISTS topics,
|
||||
DROP COLUMN IF EXISTS only_admin_can_post,
|
||||
DROP COLUMN IF EXISTS only_admin_can_see_members;
|
||||
|
||||
COMMIT;
|
||||
Loading…
Reference in a new issue