Resolve #5939
This commit is contained in:
		
							parent
							
								
									84958af4ce
								
							
						
					
					
						commit
						65c0b6c7da
					
				
					 10 changed files with 123 additions and 9 deletions
				
			
		| 
						 | 
				
			
			@ -11,12 +11,17 @@
 | 
			
		|||
			<option value="home">{{ $t('_antennaSources.homeTimeline') }}</option>
 | 
			
		||||
			<option value="users">{{ $t('_antennaSources.users') }}</option>
 | 
			
		||||
			<option value="list">{{ $t('_antennaSources.userList') }}</option>
 | 
			
		||||
			<option value="group">{{ $t('_antennaSources.userGroup') }}</option>
 | 
			
		||||
		</mk-select>
 | 
			
		||||
		<mk-select v-model="userListId" v-if="src === 'list'">
 | 
			
		||||
			<template #label>{{ $t('userList') }}</template>
 | 
			
		||||
			<option v-for="list in userLists" :value="list.id" :key="list.id">{{ list.name }}</option>
 | 
			
		||||
		</mk-select>
 | 
			
		||||
		<mk-textarea v-model="users" v-if="src === 'users'">
 | 
			
		||||
		<mk-select v-model="userGroupId" v-else-if="src === 'group'">
 | 
			
		||||
			<template #label>{{ $t('userGroup') }}</template>
 | 
			
		||||
			<option v-for="group in userGroups" :value="group.id" :key="group.id">{{ group.name }}</option>
 | 
			
		||||
		</mk-select>
 | 
			
		||||
		<mk-textarea v-model="users" v-else-if="src === 'users'">
 | 
			
		||||
			<span>{{ $t('users') }}</span>
 | 
			
		||||
			<template #desc>{{ $t('antennaUsersDescription') }} <button class="_textButton" @click="addUser">{{ $t('addUser') }}</button></template>
 | 
			
		||||
		</mk-textarea>
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +72,7 @@ export default Vue.extend({
 | 
			
		|||
			name: '',
 | 
			
		||||
			src: '',
 | 
			
		||||
			userListId: null,
 | 
			
		||||
			userGroupId: null,
 | 
			
		||||
			users: '',
 | 
			
		||||
			keywords: '',
 | 
			
		||||
			caseSensitive: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +80,7 @@ export default Vue.extend({
 | 
			
		|||
			withFile: false,
 | 
			
		||||
			notify: false,
 | 
			
		||||
			userLists: null,
 | 
			
		||||
			userGroups: null,
 | 
			
		||||
			faSave, faTrash
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
| 
						 | 
				
			
			@ -83,6 +90,13 @@ export default Vue.extend({
 | 
			
		|||
			if (this.src === 'list' && this.userLists === null) {
 | 
			
		||||
				this.userLists = await this.$root.api('users/lists/list');
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (this.src === 'group' && this.userGroups === null) {
 | 
			
		||||
				const groups1 = await this.$root.api('users/groups/owned');
 | 
			
		||||
				const groups2 = await this.$root.api('users/groups/joined');
 | 
			
		||||
 | 
			
		||||
				this.userGroups = [...groups1, ...groups2];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -90,6 +104,7 @@ export default Vue.extend({
 | 
			
		|||
		this.name = this.antenna.name;
 | 
			
		||||
		this.src = this.antenna.src;
 | 
			
		||||
		this.userListId = this.antenna.userListId;
 | 
			
		||||
		this.userGroupId = this.antenna.userGroupId;
 | 
			
		||||
		this.users = this.antenna.users.join('\n');
 | 
			
		||||
		this.keywords = this.antenna.keywords.map(x => x.join(' ')).join('\n');
 | 
			
		||||
		this.caseSensitive = this.antenna.caseSensitive;
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +120,7 @@ export default Vue.extend({
 | 
			
		|||
					name: this.name,
 | 
			
		||||
					src: this.src,
 | 
			
		||||
					userListId: this.userListId,
 | 
			
		||||
					userGroupId: this.userGroupId,
 | 
			
		||||
					withReplies: this.withReplies,
 | 
			
		||||
					withFile: this.withFile,
 | 
			
		||||
					notify: this.notify,
 | 
			
		||||
| 
						 | 
				
			
			@ -119,6 +135,7 @@ export default Vue.extend({
 | 
			
		|||
					name: this.name,
 | 
			
		||||
					src: this.src,
 | 
			
		||||
					userListId: this.userListId,
 | 
			
		||||
					userGroupId: this.userGroupId,
 | 
			
		||||
					withReplies: this.withReplies,
 | 
			
		||||
					withFile: this.withFile,
 | 
			
		||||
					notify: this.notify,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,6 +50,7 @@ export default Vue.extend({
 | 
			
		|||
				name: '',
 | 
			
		||||
				src: 'all',
 | 
			
		||||
				userListId: null,
 | 
			
		||||
				userGroupId: null,
 | 
			
		||||
				users: [],
 | 
			
		||||
				keywords: [],
 | 
			
		||||
				withReplies: false,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,10 @@
 | 
			
		|||
import { Antenna } from '../models/entities/antenna';
 | 
			
		||||
import { Note } from '../models/entities/note';
 | 
			
		||||
import { User } from '../models/entities/user';
 | 
			
		||||
import { UserListJoinings } from '../models';
 | 
			
		||||
import { UserListJoinings, UserGroupJoinings } from '../models';
 | 
			
		||||
import parseAcct from './acct/parse';
 | 
			
		||||
import { getFullApAccount } from './convert-host';
 | 
			
		||||
import { ensure } from '../prelude/ensure';
 | 
			
		||||
 | 
			
		||||
export async function checkHitAntenna(antenna: Antenna, note: Note, noteUser: User, followers: User['id'][]): Promise<boolean> {
 | 
			
		||||
	if (note.visibility === 'specified') return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +23,14 @@ export async function checkHitAntenna(antenna: Antenna, note: Note, noteUser: Us
 | 
			
		|||
		})).map(x => x.userId);
 | 
			
		||||
 | 
			
		||||
		if (!listUsers.includes(note.userId)) return false;
 | 
			
		||||
	} else if (antenna.src === 'group') {
 | 
			
		||||
		const joining = await UserGroupJoinings.findOne(antenna.userGroupJoiningId!).then(ensure);
 | 
			
		||||
 | 
			
		||||
		const groupUsers = (await UserGroupJoinings.find({
 | 
			
		||||
			userGroupId: joining.userGroupId
 | 
			
		||||
		})).map(x => x.userId);
 | 
			
		||||
 | 
			
		||||
		if (!groupUsers.includes(note.userId)) return false;
 | 
			
		||||
	} else if (antenna.src === 'users') {
 | 
			
		||||
		const accts = antenna.users.map(x => {
 | 
			
		||||
			const { username, host } = parseAcct(x);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typ
 | 
			
		|||
import { User } from './user';
 | 
			
		||||
import { id } from '../id';
 | 
			
		||||
import { UserList } from './user-list';
 | 
			
		||||
import { UserGroupJoining } from './user-group-joining';
 | 
			
		||||
 | 
			
		||||
@Entity()
 | 
			
		||||
export class Antenna {
 | 
			
		||||
| 
						 | 
				
			
			@ -32,8 +33,8 @@ export class Antenna {
 | 
			
		|||
	})
 | 
			
		||||
	public name: string;
 | 
			
		||||
 | 
			
		||||
	@Column('enum', { enum: ['home', 'all', 'users', 'list'] })
 | 
			
		||||
	public src: 'home' | 'all' | 'users' | 'list';
 | 
			
		||||
	@Column('enum', { enum: ['home', 'all', 'users', 'list', 'group'] })
 | 
			
		||||
	public src: 'home' | 'all' | 'users' | 'list' | 'group';
 | 
			
		||||
 | 
			
		||||
	@Column({
 | 
			
		||||
		...id(),
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +48,18 @@ export class Antenna {
 | 
			
		|||
	@JoinColumn()
 | 
			
		||||
	public userList: UserList | null;
 | 
			
		||||
 | 
			
		||||
	@Column({
 | 
			
		||||
		...id(),
 | 
			
		||||
		nullable: true
 | 
			
		||||
	})
 | 
			
		||||
	public userGroupJoiningId: UserGroupJoining['id'] | null;
 | 
			
		||||
 | 
			
		||||
	@ManyToOne(type => UserGroupJoining, {
 | 
			
		||||
		onDelete: 'CASCADE'
 | 
			
		||||
	})
 | 
			
		||||
	@JoinColumn()
 | 
			
		||||
	public userGroupJoining: UserGroupJoining | null;
 | 
			
		||||
 | 
			
		||||
	@Column('varchar', {
 | 
			
		||||
		length: 1024, array: true,
 | 
			
		||||
		default: '{}'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ import { EntityRepository, Repository } from 'typeorm';
 | 
			
		|||
import { Antenna } from '../entities/antenna';
 | 
			
		||||
import { ensure } from '../../prelude/ensure';
 | 
			
		||||
import { SchemaType } from '../../misc/schema';
 | 
			
		||||
import { AntennaNotes } from '..';
 | 
			
		||||
import { AntennaNotes, UserGroupJoinings } from '..';
 | 
			
		||||
 | 
			
		||||
export type PackedAntenna = SchemaType<typeof packedAntennaSchema>;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ export class AntennaRepository extends Repository<Antenna> {
 | 
			
		|||
		const antenna = typeof src === 'object' ? src : await this.findOne(src).then(ensure);
 | 
			
		||||
 | 
			
		||||
		const hasUnreadNote = (await AntennaNotes.findOne({ antennaId: antenna.id, read: false })) != null;
 | 
			
		||||
		const userGroupJoining = antenna.userGroupJoiningId ? await UserGroupJoinings.findOne(antenna.userGroupJoiningId) : null;
 | 
			
		||||
 | 
			
		||||
		return {
 | 
			
		||||
			id: antenna.id,
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +23,7 @@ export class AntennaRepository extends Repository<Antenna> {
 | 
			
		|||
			keywords: antenna.keywords,
 | 
			
		||||
			src: antenna.src,
 | 
			
		||||
			userListId: antenna.userListId,
 | 
			
		||||
			userGroupId: userGroupJoining ? userGroupJoining.userGroupId : null,
 | 
			
		||||
			users: antenna.users,
 | 
			
		||||
			caseSensitive: antenna.caseSensitive,
 | 
			
		||||
			notify: antenna.notify,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import $ from 'cafy';
 | 
			
		||||
import define from '../../define';
 | 
			
		||||
import { genId } from '../../../../misc/gen-id';
 | 
			
		||||
import { Antennas, UserLists } from '../../../../models';
 | 
			
		||||
import { Antennas, UserLists, UserGroupJoinings } from '../../../../models';
 | 
			
		||||
import { ID } from '../../../../misc/cafy-id';
 | 
			
		||||
import { ApiError } from '../../error';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,13 +18,17 @@ export const meta = {
 | 
			
		|||
		},
 | 
			
		||||
 | 
			
		||||
		src: {
 | 
			
		||||
			validator: $.str.or(['home', 'all', 'users', 'list'])
 | 
			
		||||
			validator: $.str.or(['home', 'all', 'users', 'list', 'group'])
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		userListId: {
 | 
			
		||||
			validator: $.nullable.optional.type(ID),
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		userGroupId: {
 | 
			
		||||
			validator: $.nullable.optional.type(ID),
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		keywords: {
 | 
			
		||||
			validator: $.arr($.arr($.str))
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -55,12 +59,19 @@ export const meta = {
 | 
			
		|||
			message: 'No such user list.',
 | 
			
		||||
			code: 'NO_SUCH_USER_LIST',
 | 
			
		||||
			id: '95063e93-a283-4b8b-9aa5-bcdb8df69a7f'
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		noSuchUserGroup: {
 | 
			
		||||
			message: 'No such user group.',
 | 
			
		||||
			code: 'NO_SUCH_USER_GROUP',
 | 
			
		||||
			id: 'aa3c0b9a-8cae-47c0-92ac-202ce5906682'
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default define(meta, async (ps, user) => {
 | 
			
		||||
	let userList;
 | 
			
		||||
	let userGroupJoining;
 | 
			
		||||
 | 
			
		||||
	if (ps.src === 'list') {
 | 
			
		||||
		userList = await UserLists.findOne({
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +82,15 @@ export default define(meta, async (ps, user) => {
 | 
			
		|||
		if (userList == null) {
 | 
			
		||||
			throw new ApiError(meta.errors.noSuchUserList);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (ps.src === 'group') {
 | 
			
		||||
		userGroupJoining = await UserGroupJoinings.findOne({
 | 
			
		||||
			userGroupId: ps.userGroupId,
 | 
			
		||||
			userId: user.id,
 | 
			
		||||
		});
 | 
			
		||||
	
 | 
			
		||||
		if (userGroupJoining == null) {
 | 
			
		||||
			throw new ApiError(meta.errors.noSuchUserGroup);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const antenna = await Antennas.save({
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +100,7 @@ export default define(meta, async (ps, user) => {
 | 
			
		|||
		name: ps.name,
 | 
			
		||||
		src: ps.src,
 | 
			
		||||
		userListId: userList ? userList.id : null,
 | 
			
		||||
		userGroupJoiningId: userGroupJoining ? userGroupJoining.id : null,
 | 
			
		||||
		keywords: ps.keywords,
 | 
			
		||||
		users: ps.users,
 | 
			
		||||
		caseSensitive: ps.caseSensitive,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ import $ from 'cafy';
 | 
			
		|||
import { ID } from '../../../../misc/cafy-id';
 | 
			
		||||
import define from '../../define';
 | 
			
		||||
import { ApiError } from '../../error';
 | 
			
		||||
import { Antennas, UserLists } from '../../../../models';
 | 
			
		||||
import { Antennas, UserLists, UserGroupJoinings } from '../../../../models';
 | 
			
		||||
 | 
			
		||||
export const meta = {
 | 
			
		||||
	tags: ['antennas'],
 | 
			
		||||
| 
						 | 
				
			
			@ -21,13 +21,17 @@ export const meta = {
 | 
			
		|||
		},
 | 
			
		||||
 | 
			
		||||
		src: {
 | 
			
		||||
			validator: $.str.or(['home', 'all', 'users', 'list'])
 | 
			
		||||
			validator: $.str.or(['home', 'all', 'users', 'list', 'group'])
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		userListId: {
 | 
			
		||||
			validator: $.nullable.optional.type(ID),
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		userGroupId: {
 | 
			
		||||
			validator: $.nullable.optional.type(ID),
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		keywords: {
 | 
			
		||||
			validator: $.arr($.arr($.str))
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -64,6 +68,12 @@ export const meta = {
 | 
			
		|||
			message: 'No such user list.',
 | 
			
		||||
			code: 'NO_SUCH_USER_LIST',
 | 
			
		||||
			id: '1c6b35c9-943e-48c2-81e4-2844989407f7'
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		noSuchUserGroup: {
 | 
			
		||||
			message: 'No such user group.',
 | 
			
		||||
			code: 'NO_SUCH_USER_GROUP',
 | 
			
		||||
			id: '109ed789-b6eb-456e-b8a9-6059d567d385'
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +90,7 @@ export default define(meta, async (ps, user) => {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	let userList;
 | 
			
		||||
	let userGroupJoining;
 | 
			
		||||
 | 
			
		||||
	if (ps.src === 'list') {
 | 
			
		||||
		userList = await UserLists.findOne({
 | 
			
		||||
| 
						 | 
				
			
			@ -90,12 +101,22 @@ export default define(meta, async (ps, user) => {
 | 
			
		|||
		if (userList == null) {
 | 
			
		||||
			throw new ApiError(meta.errors.noSuchUserList);
 | 
			
		||||
		}
 | 
			
		||||
	} else if (ps.src === 'group') {
 | 
			
		||||
		userGroupJoining = await UserGroupJoinings.findOne({
 | 
			
		||||
			userGroupId: ps.userGroupId,
 | 
			
		||||
			userId: user.id,
 | 
			
		||||
		});
 | 
			
		||||
	
 | 
			
		||||
		if (userGroupJoining == null) {
 | 
			
		||||
			throw new ApiError(meta.errors.noSuchUserGroup);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	await Antennas.update(antenna.id, {
 | 
			
		||||
		name: ps.name,
 | 
			
		||||
		src: ps.src,
 | 
			
		||||
		userListId: userList ? userList.id : null,
 | 
			
		||||
		userGroupJoiningId: userGroupJoining ? userGroupJoining.id : null,
 | 
			
		||||
		keywords: ps.keywords,
 | 
			
		||||
		users: ps.users,
 | 
			
		||||
		caseSensitive: ps.caseSensitive,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue