Export/Import withReplies (#15986)
* feat: export withReplies of UserList * feat: export withReplies of following * import following時のwithRepliesがデフォルト値であることを明示する * changelog * update index.d.ts --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
parent
367dac4edd
commit
1214d1d8fc
|
@ -57,6 +57,7 @@
|
||||||
- Fix: Twitchのクリップがプレイヤーで再生できない問題を修正
|
- Fix: Twitchのクリップがプレイヤーで再生できない問題を修正
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
|
- Enhance: リストやフォローをエクスポートする際にリプライを含むかどうかの情報を含むように
|
||||||
- Enhance: チャットルームの最大メンバー数を30人から50人に調整
|
- Enhance: チャットルームの最大メンバー数を30人から50人に調整
|
||||||
- Enhance: ノートのレスポンスにアンケートが添付されているかどうかを示すフラグ`hasPoll`を追加
|
- Enhance: ノートのレスポンスにアンケートが添付されているかどうかを示すフラグ`hasPoll`を追加
|
||||||
- Enhance: チャットルームのレスポンスに招待されているかどうかを示すフラグ`invitationExists`を追加
|
- Enhance: チャットルームのレスポンスに招待されているかどうかを示すフラグ`invitationExists`を追加
|
||||||
|
|
|
@ -9707,7 +9707,7 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"excludeInactiveUsers": string;
|
"excludeInactiveUsers": string;
|
||||||
/**
|
/**
|
||||||
* インポートした人による返信をTLに含むようにする
|
* 返信をTLに含むかの情報がファイルにない場合に、インポートした人による返信をTLに含むようにする
|
||||||
*/
|
*/
|
||||||
"withReplies": string;
|
"withReplies": string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2556,7 +2556,7 @@ _exportOrImport:
|
||||||
userLists: "リスト"
|
userLists: "リスト"
|
||||||
excludeMutingUsers: "ミュートしているユーザーを除外"
|
excludeMutingUsers: "ミュートしているユーザーを除外"
|
||||||
excludeInactiveUsers: "使われていないアカウントを除外"
|
excludeInactiveUsers: "使われていないアカウントを除外"
|
||||||
withReplies: "インポートした人による返信をTLに含むようにする"
|
withReplies: "返信をTLに含むかの情報がファイルにない場合に、インポートした人による返信をTLに含むようにする"
|
||||||
|
|
||||||
_charts:
|
_charts:
|
||||||
federation: "連合"
|
federation: "連合"
|
||||||
|
|
|
@ -91,7 +91,7 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async addMember(target: MiUser, list: MiUserList, me: MiUser) {
|
public async addMember(target: MiUser, list: MiUserList, me: MiUser, options: { withReplies?: boolean } = {}) {
|
||||||
const currentCount = await this.userListMembershipsRepository.countBy({
|
const currentCount = await this.userListMembershipsRepository.countBy({
|
||||||
userListId: list.id,
|
userListId: list.id,
|
||||||
});
|
});
|
||||||
|
@ -104,6 +104,7 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit {
|
||||||
userId: target.id,
|
userId: target.id,
|
||||||
userListId: list.id,
|
userListId: list.id,
|
||||||
userListUserId: list.userId,
|
userListUserId: list.userId,
|
||||||
|
withReplies: options.withReplies ?? false,
|
||||||
} as MiUserListMembership);
|
} as MiUserListMembership);
|
||||||
|
|
||||||
this.globalEventService.publishInternalEvent('userListMemberAdded', { userListId: list.id, memberId: target.id });
|
this.globalEventService.publishInternalEvent('userListMemberAdded', { userListId: list.id, memberId: target.id });
|
||||||
|
|
|
@ -94,7 +94,8 @@ export class ExportFollowingProcessorService {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = this.utilityService.getFullApAccount(u.username, u.host);
|
const userAcct = this.utilityService.getFullApAccount(u.username, u.host);
|
||||||
|
const content = `${userAcct},withReplies=${following.withReplies}`;
|
||||||
await new Promise<void>((res, rej) => {
|
await new Promise<void>((res, rej) => {
|
||||||
stream.write(content + '\n', err => {
|
stream.write(content + '\n', err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -67,10 +67,12 @@ export class ExportUserListsProcessorService {
|
||||||
const users = await this.usersRepository.findBy({
|
const users = await this.usersRepository.findBy({
|
||||||
id: In(memberships.map(j => j.userId)),
|
id: In(memberships.map(j => j.userId)),
|
||||||
});
|
});
|
||||||
|
const usersWithReplies = new Set(memberships.filter(m => m.withReplies).map(m => m.userId));
|
||||||
|
|
||||||
for (const u of users) {
|
for (const u of users) {
|
||||||
const acct = this.utilityService.getFullApAccount(u.username, u.host);
|
const acct = this.utilityService.getFullApAccount(u.username, u.host);
|
||||||
const content = `${list.name},${acct}`;
|
// 3rd column and later will be key=value pairs
|
||||||
|
const content = `${list.name},${acct},withReplies=${usersWithReplies.has(u.id)}`;
|
||||||
await new Promise<void>((res, rej) => {
|
await new Promise<void>((res, rej) => {
|
||||||
stream.write(content + '\n', err => {
|
stream.write(content + '\n', err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -67,8 +67,19 @@ export class ImportFollowingProcessorService {
|
||||||
const user = job.data.user;
|
const user = job.data.user;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const acct = line.split(',')[0].trim();
|
const parts = line.split(',');
|
||||||
|
const acct = parts[0].trim();
|
||||||
const { username, host } = Acct.parse(acct);
|
const { username, host } = Acct.parse(acct);
|
||||||
|
let withReplies: boolean | null = null;
|
||||||
|
|
||||||
|
for (const keyValue of parts.slice(2)) {
|
||||||
|
const [key, value] = keyValue.split('=');
|
||||||
|
switch (key) {
|
||||||
|
case 'withReplies':
|
||||||
|
withReplies = value === 'true';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!host) return;
|
if (!host) return;
|
||||||
|
|
||||||
|
@ -95,7 +106,7 @@ export class ImportFollowingProcessorService {
|
||||||
|
|
||||||
this.logger.info(`Follow ${target.id} ${job.data.withReplies ? 'with replies' : 'without replies'} ...`);
|
this.logger.info(`Follow ${target.id} ${job.data.withReplies ? 'with replies' : 'without replies'} ...`);
|
||||||
|
|
||||||
this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true, withReplies: job.data.withReplies }]);
|
await this.queueService.createFollowJob([{ from: user, to: { id: target.id }, silent: true, withReplies: withReplies ?? job.data.withReplies }]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.warn(`Error: ${e}`);
|
this.logger.warn(`Error: ${e}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,19 @@ export class ImportUserListsProcessorService {
|
||||||
linenum++;
|
linenum++;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const listName = line.split(',')[0].trim();
|
const parts = line.split(',');
|
||||||
const { username, host } = Acct.parse(line.split(',')[1].trim());
|
const listName = parts[0].trim();
|
||||||
|
const { username, host } = Acct.parse(parts[1].trim());
|
||||||
|
let withReplies = false;
|
||||||
|
|
||||||
|
for (const keyValue of parts.slice(2)) {
|
||||||
|
const [key, value] = keyValue.split('=');
|
||||||
|
switch (key) {
|
||||||
|
case 'withReplies':
|
||||||
|
withReplies = value === 'true';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let list = await this.userListsRepository.findOneBy({
|
let list = await this.userListsRepository.findOneBy({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
|
@ -100,7 +111,9 @@ export class ImportUserListsProcessorService {
|
||||||
|
|
||||||
if (await this.userListMembershipsRepository.findOneBy({ userListId: list!.id, userId: target.id }) != null) continue;
|
if (await this.userListMembershipsRepository.findOneBy({ userListId: list!.id, userId: target.id }) != null) continue;
|
||||||
|
|
||||||
this.userListService.addMember(target, list!, user);
|
await this.userListService.addMember(target, list, user, {
|
||||||
|
withReplies: withReplies,
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.warn(`Error in line:${linenum} ${e}`);
|
this.logger.warn(`Error in line:${linenum} ${e}`);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue