Skip to content

Commit 1bc9ced

Browse files
committed
Merge branch 'feat-signup-approval' of https://github.com/kokonect-link/cherrypick into develop
2 parents 9665340 + 9e91c45 commit 1bc9ced

42 files changed

Lines changed: 1011 additions & 8 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG_CHERRYPICK.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
**기반 Misskey 버전**: 2025.12.0
77
Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2025120](CHANGELOG.md#2025120) 문서를 참고하십시오.
88

9+
### General
10+
- Feat: 가입 승인 (TransFem-org/Sharkey [@2f2d88dc](https://activitypub.software/TransFem-org/Sharkey/-/commit/2f2d88dcfc76bac6815d60fa9915b8e797853292#), [@32fc540d](https://activitypub.software/TransFem-org/Sharkey/-/commit/32fc540df4a77076e3365e5471e13ea45a04c508), [@07b72c65](https://activitypub.software/TransFem-org/Sharkey/-/commit/07b72c65b93bff5f13afe28252f4aebf8adac471), [@e1f13f64](https://activitypub.software/TransFem-org/Sharkey/-/commit/e1f13f641e3e0528571e41475cda1718cac4c532), [@288fa114](https://activitypub.software/TransFem-org/Sharkey/-/commit/288fa1143d3a2c8a92a84ee1c4ea7661e0554c4c), [@6e2eabbb](https://activitypub.software/TransFem-org/Sharkey/-/commit/6e2eabbbc9ad02e6e90caa27ce7e1ccb0b8208f6), [@c3f76818](https://activitypub.software/TransFem-org/Sharkey/-/commit/c3f768181ae232a9ac03c69759f5508398b4cd55), [@142f500f](https://activitypub.software/TransFem-org/Sharkey/-/commit/142f500f4bbf3208380b83a4c7764bfe411950ab), [@1d9cb4fa](https://activitypub.software/TransFem-org/Sharkey/-/commit/1d9cb4fad9e825c3389e73f50fa396338b159b5c), [@42530b5a](https://activitypub.software/TransFem-org/Sharkey/-/commit/42530b5a39f0bce386bf408004d1584bf7a36576), [@fea7889e](https://activitypub.software/TransFem-org/Sharkey/-/commit/fea7889e0cd5ed223a4db9cb668be684cead2a52))
11+
- 초대 코드를 공유하지 않고도 가입 사유를 확인해 원하는 유저만 가입을 승인할 수 있습니다.
12+
- 가입을 승인하면 해당 유저에게 가입이 승인되었음을 알리는 이메일이 전송됩니다.
13+
- 가입 사유는 관리자 및 모더레이터 권한이 있는 유저만 확인할 수 있습니다.
14+
915
### Client
1016
- Fix: 답글란의 입력란에서 `입력란 도움말 표시`가 작동하지 않을 수 있음
1117
- Fix: 화면 크기가 작은 디바이스에서 답글란의 입력란 디자인이 잘못된 디자인으로 표시될 수 있음

locales/en-US.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
---
22
_lang_: "English"
3+
approveConfirm: "Are you sure that you want to approve this account?"
4+
approvalRequiredForSignup: "Require approval for new users"
5+
approveAccount: "Approve"
6+
denyAccount: "Deny & Delete"
7+
approved: "Approved"
8+
notApproved: "Not Approved"
9+
approvalStatus: "Approval Status"
10+
approvalRequiredToRegister: "This instance is only accepting users who specify a reason for registration."
11+
pendingUserApprovals: "There are users awaiting approval."
12+
approvals: "Sign-up approvals"
13+
deleteThisAccountConfirm: "This will irreversibly delete this account. Proceed?"
14+
signupReason: "Sign-up reason"
315
compareContent: "Compare content"
416
editHistory: "Edit history"
517
unRenoteAll: "Remove all renote from notes"
@@ -2445,6 +2457,8 @@ _signup:
24452457
almostThere: "Almost there"
24462458
emailAddressInfo: "Please enter your email address. It will not be made public."
24472459
emailSent: "A confirmation email has been sent to your email address ({email}). Please click the included link to complete account creation.\nIf you do not receive an email, please check your spam folder."
2460+
approvalPending: "Your account has been created and is awaiting approval."
2461+
reasonInfo: "Please enter a reason as to why you want to join the instance."
24482462
_accountDelete:
24492463
accountDelete: "Delete account"
24502464
mayTakeTime: "As account deletion is a resource-heavy process, it may take some time to complete depending on how much content you have created and how many files you have uploaded."
@@ -2867,6 +2881,8 @@ _permissions:
28672881
"write:report-abuse": "Report violation"
28682882
"write:chat": "Compose or delete chat messages"
28692883
"read:chat": "Browse Chat"
2884+
"write:admin:approve-user": "Approve new users"
2885+
"write:admin:decline-user": "Decline new users"
28702886
_auth:
28712887
shareAccessTitle: "Granting application permissions"
28722888
shareAccess: "Would you like to authorize \"{name}\" to access this account?"
@@ -3328,6 +3344,8 @@ _moderationLogTypes:
33283344
deleteGalleryPost: "Gallery post deleted"
33293345
deleteChatRoom: "Deleted Chat Room"
33303346
updateProxyAccountDescription: "Update the description of the proxy account"
3347+
approve: "Approved"
3348+
decline: "Declined"
33313349
_fileViewer:
33323350
title: "File details"
33333351
type: "File type"

locales/ja-JP.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
_lang_: "日本語"
22

3+
approveConfirm: "このアカウントを承認してもよろしいですか?"
4+
approvalRequiredForSignup: "新規ユーザーの承認が必要"
5+
approveAccount: "承認する"
6+
denyAccount: "拒否と削除"
7+
approved: "承認済み"
8+
notApproved: "承認されていない"
9+
approvalStatus: "承認状況"
10+
approvalRequiredToRegister: "このインスタンスは、登録理由を指定したユーザーのみを受け入れています。"
11+
pendingUserApprovals: "承認待ちのユーザーがいる。"
12+
approvals: "登録承認"
13+
deleteThisAccountConfirm: "このアカウントは永久に削除されます。続けましょうか?"
14+
signupReason: "登録理由"
315
compareContent: "内容比較"
416
editHistory: "修正履歴"
517
unRenoteAll: "全リノート解除"
@@ -2484,6 +2496,8 @@ _signup:
24842496
almostThere: "ほとんど完了です"
24852497
emailAddressInfo: "あなたが使っているメールアドレスを入力してください。メールアドレスが公開されることはありません。"
24862498
emailSent: "入力されたメールアドレス({email})宛に確認のメールが送信されました。メールに記載されたリンクにアクセスすると、アカウントの作成が完了します。\nもしメールが来なかったらスパムメールボックスを確認してください。\nメールに記載されているリンクの有効期限は30分です。"
2499+
approvalPending: "アカウントが作成され、承認待ちの状態です。"
2500+
reasonInfo: "インスタンスに参加したい理由を入力してください。"
24872501

24882502
_accountDelete:
24892503
accountDelete: "アカウントの削除"
@@ -2932,6 +2946,8 @@ _permissions:
29322946
"write:report-abuse": "違反を報告する"
29332947
"write:chat": "ダイレクトメッセージを操作する"
29342948
"read:chat": "ダイレクトメッセージを閲覧する"
2949+
"write:admin:approve-user": "新規ユーザー登録承認"
2950+
"write:admin:decline-user": "新規ユーザー登録拒否"
29352951

29362952
_auth:
29372953
shareAccessTitle: "アプリへのアクセス許可"
@@ -3430,6 +3446,8 @@ _moderationLogTypes:
34303446
deleteGalleryPost: "ギャラリーの投稿を削除"
34313447
deleteChatRoom: "ダイレクトメッセージのグループを削除"
34323448
updateProxyAccountDescription: "プロキシアカウントの説明を更新"
3449+
approve: "承認済み"
3450+
decline: "拒否"
34333451

34343452
_fileViewer:
34353453
title: "ファイルの詳細"

locales/ko-KR.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
---
22
_lang_: "한국어"
3+
approveConfirm: "이 계정을 승인할까요?"
4+
approvalRequiredForSignup: "가입 시 승인 필요"
5+
approveAccount: "승인"
6+
denyAccount: "거부 및 삭제"
7+
approved: "승인됨"
8+
notApproved: "승인되지 않음"
9+
approvalStatus: "승인 상태"
10+
approvalRequiredToRegister: "이 서버는 가입 목적을 작성한 사용자만 승인하고 있어요."
11+
pendingUserApprovals: "승인 대기 중인 사용자가 있어요."
12+
approvals: "가입 승인"
13+
deleteThisAccountConfirm: "이 계정은 영구적으로 삭제돼요. 계속할까요?"
14+
signupReason: "가입하려는 목적"
315
compareContent: "내용 비교하기"
416
editHistory: "편집 기록"
517
unRenoteAll: "모든 리노트 삭제"
@@ -2447,6 +2459,8 @@ _signup:
24472459
almostThere: "거의 다 끝났어요!"
24482460
emailAddressInfo: "사용할 메일 주소를 입력해 주세요. 이메일 주소는 다른 사용자에게 공개되지 않아요."
24492461
emailSent: "입력한 메일 주소({email})로 확인 메일을 보내드렸어요! 가입을 완료하려면 보내드린 메일에 있는 링크로 접속해 주세요.\n만약 메일이 오지 않는다면 스팸 메일함을 확인해 주세요!"
2462+
approvalPending: "계정이 생성되어 승인 대기 중이에요."
2463+
reasonInfo: "이 서버에 가입하려는 목적을 입력해 주세요."
24502464
_accountDelete:
24512465
accountDelete: "계정 삭제"
24522466
mayTakeTime: "계정 삭제는 서버에 부하를 가하기 때문에, 작성한 콘텐츠나 업로드한 파일의 수가 많으면 완료까지 시간이 걸릴 수 있어요."
@@ -2869,6 +2883,8 @@ _permissions:
28692883
"write:report-abuse": "위반 내용 신고하기"
28702884
"write:chat": "대화를 시작하거나 쪽지 보내기"
28712885
"read:chat": "쪽지 읽기"
2886+
"write:admin:approve-user": "신규 사용자 가입 승인"
2887+
"write:admin:decline-user": "신규 사용자 가입 거부"
28722888
_auth:
28732889
shareAccessTitle: "애플리케이션 접근 허가"
28742890
shareAccess: "‘{name}’에서 계정에 접근하는 것을 허용할까요?"
@@ -3330,6 +3346,8 @@ _moderationLogTypes:
33303346
deleteGalleryPost: "갤러리 게시물 삭제"
33313347
deleteChatRoom: "그룹 삭제"
33323348
updateProxyAccountDescription: "프록시 계정 설명 업데이트"
3349+
approve: "승인됨"
3350+
decline: "거부됨"
33333351
_fileViewer:
33343352
title: "파일 상세"
33353353
type: "파일 유형"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* SPDX-FileCopyrightText: noridev and cherrypick-project
3+
* SPDX-License-Identifier: AGPL-3.0-only
4+
*/
5+
6+
export class ApprovalSignup1768893580518 {
7+
name = 'ApprovalSignup1768893580518'
8+
9+
async up(queryRunner) {
10+
await queryRunner.query(`ALTER TABLE "meta" ADD "approvalRequiredForSignup" boolean DEFAULT false NOT NULL`);
11+
await queryRunner.query(`ALTER TABLE "user" ADD "approved" boolean DEFAULT false NOT NULL`);
12+
await queryRunner.query(`ALTER TABLE "user" ADD "signupReason" character varying(1000) NULL`);
13+
await queryRunner.query(`ALTER TABLE "user_pending" ADD "reason" character varying(1000) NULL`);
14+
}
15+
16+
async down(queryRunner) {
17+
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "approvalRequiredForSignup"`);
18+
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "approved"`);
19+
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "signupReason"`);
20+
await queryRunner.query(`ALTER TABLE "user_pending" DROP COLUMN "reason"`);
21+
}
22+
}

packages/backend/src/core/SignupService.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ export class SignupService {
5656
passwordHash?: MiUserProfile['password'] | null;
5757
host?: string | null;
5858
ignorePreservedUsernames?: boolean;
59+
reason?: string | null;
5960
}) {
60-
const { username, password, passwordHash, host } = opts;
61+
const { username, password, passwordHash, host, reason } = opts;
6162
let hash = passwordHash;
63+
const instance = await this.metaService.fetch(true);
6264

6365
// Validate username
6466
if (!this.userEntityService.validateLocalUsername(username)) {
@@ -119,6 +121,9 @@ export class SignupService {
119121
));
120122

121123
let account!: MiUser;
124+
let defaultApproval = false;
125+
126+
if (!instance.approvalRequiredForSignup) defaultApproval = true;
122127

123128
// Start transaction
124129
await this.db.transaction(async transactionalEntityManager => {
@@ -135,6 +140,8 @@ export class SignupService {
135140
usernameLower: username.toLowerCase(),
136141
host: this.utilityService.toPunyNullable(host),
137142
token: secret,
143+
approved: defaultApproval,
144+
signupReason: reason,
138145
}));
139146

140147
await transactionalEntityManager.save(new MiUserKeypair({

packages/backend/src/core/entities/MetaEntityService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ export class MetaEntityService {
142142
noteSearchableScope: (this.config.meilisearch == null || this.config.meilisearch.scope !== 'local') ? 'global' : 'local',
143143
maxFileSize: this.config.maxFileSize,
144144
federation: this.meta.federation,
145+
approvalRequiredForSignup: instance.approvalRequiredForSignup,
145146
};
146147

147148
return packed;

packages/backend/src/core/entities/UserEntityService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ export class UserEntityService implements OnModuleInit {
533533
) : undefined,
534534
setFederationAvatarShape: user.setFederationAvatarShape ?? undefined,
535535
isSquareAvatars: user.isSquareAvatars ?? undefined,
536+
approved: user.approved,
536537

537538
...(isDetailed ? {
538539
url: profile!.url,
@@ -645,6 +646,7 @@ export class UserEntityService implements OnModuleInit {
645646
},
646647
})
647648
: [],
649+
signupReason: user.signupReason,
648650
} : {}),
649651

650652
...(relation ? {

packages/backend/src/models/Meta.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,11 @@ export class MiMeta {
920920
length: 2048, nullable: true,
921921
})
922922
public customRobotsTxt: string | null;
923+
924+
@Column('boolean', {
925+
default: false,
926+
})
927+
public approvalRequiredForSignup: boolean;
923928
}
924929

925930
export type SoftwareSuspension = {

packages/backend/src/models/User.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,16 @@ export class MiUser {
314314
})
315315
public canChat: boolean | null;
316316

317+
@Column('boolean', {
318+
default: false,
319+
})
320+
public approved: boolean;
321+
322+
@Column('varchar', {
323+
length: 1000, nullable: true,
324+
})
325+
public signupReason: string | null;
326+
317327
constructor(data: Partial<MiUser>) {
318328
if (data == null) return;
319329

0 commit comments

Comments
 (0)