feat(koi): bumped sharkey + added no-xpost extension

This commit is contained in:
alina 🌸 2024-07-27 21:01:44 +03:00
parent a6a2482aac
commit 710fda269a
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
4 changed files with 250 additions and 7 deletions

View file

@ -1,6 +1,6 @@
# based on https://activitypub.software/TransFem-org/Sharkey/-/blob/develop/Dockerfile
ARG NODE_VERSION=20.12.2-alpine3.19
ARG COMMIT=717696c4728d2e507ddfbd0e4890189758ab1087
ARG COMMIT=c344705d6708fdc725d6122d2b321cb2d01dad4b
FROM node:${NODE_VERSION} as build
@ -38,6 +38,7 @@ RUN git apply /patches/webhook-notification.patch
# motivation: https://very.stupid.fish/notes/9shhrn2qncid008s
RUN git apply /patches/index-everything.patch
RUN git apply /patches/no-remote-users.patch
RUN git apply /patches/no-xpost-extension.patch
RUN cp -f /patches/robots.txt packages/backend/assets/robots.txt
# end patch

View file

@ -0,0 +1,242 @@
diff --git a/packages/backend/migration/1722103475000-no-xpost.js b/packages/backend/migration/1722103475000-no-xpost.js
new file mode 100644
index 0000000..8818c37
--- /dev/null
+++ b/packages/backend/migration/1722103475000-no-xpost.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class NoXpost1722103475000 {
+ name = 'NoXpost1722103475000'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "note" ADD "noXpost" boolean NOT NULL DEFAULT false`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "noXpost"`);
+ }
+}
diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index 41efa76..87a388e 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -149,6 +149,7 @@ type Option = {
uri?: string | null;
url?: string | null;
app?: MiApp | null;
+ noXpost?: boolean;
};
@Injectable()
@@ -625,6 +626,7 @@ export class NoteCreateService implements OnApplicationShutdown {
renoteUserId: data.renote ? data.renote.userId : null,
renoteUserHost: data.renote ? data.renote.userHost : null,
userHost: user.host,
+ noXpost: data.noXpost,
});
// should really not happen, but better safe than sorry
diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts
index 0cb58d0..00b4be3 100644
--- a/packages/backend/src/core/NoteEditService.ts
+++ b/packages/backend/src/core/NoteEditService.ts
@@ -141,6 +141,7 @@ type Option = {
app?: MiApp | null;
updatedAt?: Date | null;
editcount?: boolean | null;
+ noXpost?: boolean;
};
@Injectable()
@@ -494,6 +495,7 @@ export class NoteEditService implements OnApplicationShutdown {
renoteUserId: data.renote ? data.renote.userId : null,
renoteUserHost: data.renote ? data.renote.userHost : null,
userHost: user.host,
+ noXpost: data.noXpost,
});
if (data.uri != null) note.uri = data.uri;
diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts
index 90784fd..0f9769f 100644
--- a/packages/backend/src/core/activitypub/ApRendererService.ts
+++ b/packages/backend/src/core/activitypub/ApRendererService.ts
@@ -467,6 +467,7 @@ export class ApRendererService {
attachment: files.map(x => this.renderDocument(x)),
sensitive: note.cw != null || files.some(file => file.isSensitive),
tag,
+ 'desu:no-xpost': note.noXpost,
...asPoll,
};
}
@@ -759,6 +760,7 @@ export class ApRendererService {
attachment: files.map(x => this.renderDocument(x)),
sensitive: note.cw != null || files.some(file => file.isSensitive),
tag,
+ 'desu:no-xpost': note.noXpost,
...asPoll,
};
}
diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts
index 8edd8a1..4518b27 100644
--- a/packages/backend/src/core/activitypub/type.ts
+++ b/packages/backend/src/core/activitypub/type.ts
@@ -122,6 +122,7 @@ export interface IPost extends IObject {
quoteUrl?: string;
quoteUri?: string;
updated?: string;
+ 'desu:no-xpost'?: boolean;
}
export interface IQuestion extends IObject {
diff --git a/packages/backend/src/models/Note.ts b/packages/backend/src/models/Note.ts
index b11e2ec..8cf6787 100644
--- a/packages/backend/src/models/Note.ts
+++ b/packages/backend/src/models/Note.ts
@@ -235,6 +235,11 @@ export class MiNote {
comment: '[Denormalized]',
})
public renoteUserHost: string | null;
+
+ @Column('boolean', {
+ default: false,
+ })
+ public noXpost: boolean;
//#endregion
constructor(data: Partial<MiNote>) {
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index 626f03b..451f2d8 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -155,6 +155,7 @@ export const paramDef = {
noExtractMentions: { type: 'boolean', default: false },
noExtractHashtags: { type: 'boolean', default: false },
noExtractEmojis: { type: 'boolean', default: false },
+ noXpost: { type: 'boolean', default: false },
replyId: { type: 'string', format: 'misskey:id', nullable: true },
renoteId: { type: 'string', format: 'misskey:id', nullable: true },
channelId: { type: 'string', format: 'misskey:id', nullable: true },
@@ -396,6 +397,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
apMentions: ps.noExtractMentions ? [] : undefined,
apHashtags: ps.noExtractHashtags ? [] : undefined,
apEmojis: ps.noExtractEmojis ? [] : undefined,
+ noXpost: ps.noXpost,
});
return {
diff --git a/packages/backend/src/server/api/endpoints/notes/edit.ts b/packages/backend/src/server/api/endpoints/notes/edit.ts
index 835cbc1..ee2c787 100644
--- a/packages/backend/src/server/api/endpoints/notes/edit.ts
+++ b/packages/backend/src/server/api/endpoints/notes/edit.ts
@@ -203,6 +203,7 @@ export const paramDef = {
noExtractMentions: { type: 'boolean', default: false },
noExtractHashtags: { type: 'boolean', default: false },
noExtractEmojis: { type: 'boolean', default: false },
+ noXpost: { type: 'boolean', default: false },
replyId: { type: 'string', format: 'misskey:id', nullable: true },
renoteId: { type: 'string', format: 'misskey:id', nullable: true },
channelId: { type: 'string', format: 'misskey:id', nullable: true },
@@ -447,6 +448,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
apMentions: ps.noExtractMentions ? [] : undefined,
apHashtags: ps.noExtractHashtags ? [] : undefined,
apEmojis: ps.noExtractEmojis ? [] : undefined,
+ noXpost: ps.noXpost,
});
return {
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 57ed045..0d71611 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -203,6 +203,7 @@ const recentHashtags = ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]'
const imeText = ref('');
const showingOptions = ref(false);
const textAreaReadOnly = ref(false);
+const noXpost = ref(false);
const draftKey = computed((): string => {
let key = props.channel ? `channel:${props.channel.id}` : '';
@@ -471,6 +472,7 @@ function setVisibility() {
os.popup(defineAsyncComponent(() => import('@/components/MkVisibilityPicker.vue')), {
currentVisibility: visibility.value,
+ currentNoXpost: noXpost.value,
isSilenced: $i.isSilenced,
localOnly: localOnly.value,
src: visibilityButton.value,
@@ -482,6 +484,9 @@ function setVisibility() {
defaultStore.set('visibility', visibility.value);
}
},
+ changeNoXpost: v => {
+ noXpost.value = v;
+ },
}, 'closed');
}
@@ -810,6 +815,7 @@ async function post(ev?: MouseEvent) {
visibleUserIds: visibility.value === 'specified' ? visibleUsers.value.map(u => u.id) : undefined,
reactionAcceptance: reactionAcceptance.value,
editId: props.editId ? props.editId : undefined,
+ noXpost: noXpost.value,
};
if (withHashtags.value && hashtags.value && hashtags.value.trim() !== '') {
diff --git a/packages/frontend/src/components/MkVisibilityPicker.vue b/packages/frontend/src/components/MkVisibilityPicker.vue
index e0aec8b..db25745 100644
--- a/packages/frontend/src/components/MkVisibilityPicker.vue
+++ b/packages/frontend/src/components/MkVisibilityPicker.vue
@@ -37,6 +37,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<span :class="$style.itemDescription">{{ i18n.ts._visibility.specifiedDescription }}</span>
</div>
</button>
+ <MkSwitch :modelValue="noXpost" @update:modelValue="noXpostChanged" :disabled="localOnly">
+ do not cross-post
+ </MkSwitch>
</div>
</MkModal>
</template>
@@ -45,12 +48,14 @@ SPDX-License-Identifier: AGPL-3.0-only
import { nextTick, shallowRef, ref } from 'vue';
import * as Misskey from 'misskey-js';
import MkModal from '@/components/MkModal.vue';
+import MkSwitch from '@/components/MkSwitch.vue';
import { i18n } from '@/i18n.js';
const modal = shallowRef<InstanceType<typeof MkModal>>();
const props = withDefaults(defineProps<{
currentVisibility: typeof Misskey.noteVisibilities[number];
+ currentNoXpost: boolean;
isSilenced: boolean;
localOnly: boolean;
src?: HTMLElement;
@@ -60,10 +65,12 @@ const props = withDefaults(defineProps<{
const emit = defineEmits<{
(ev: 'changeVisibility', v: typeof Misskey.noteVisibilities[number]): void;
+ (ev: 'changeNoXpost', v: boolean): void;
(ev: 'closed'): void;
}>();
const v = ref(props.currentVisibility);
+const noXpost = ref(props.currentNoXpost)
function choose(visibility: typeof Misskey.noteVisibilities[number]): void {
v.value = visibility;
@@ -72,6 +79,11 @@ function choose(visibility: typeof Misskey.noteVisibilities[number]): void {
if (modal.value) modal.value.close();
});
}
+
+function noXpostChanged(v: boolean): void {
+ noXpost.value = v;
+ emit('changeNoXpost', v);
+}
</script>
<style lang="scss" module>

View file

@ -39,11 +39,11 @@ index f849e94..9ba8351 100644
@@ -30,6 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
}]"
> <!-- we re-use t_pollEnded for "edited" instead of making an identical style -->
<i v-if="notification.type === 'follow'" class="ph-plus ph-bold ph-lg"></i>
+ <i v-else-if="notification.type === 'unfollow'" class="ph-minus ph-bold ph-lg"></i>
<i v-else-if="notification.type === 'receiveFollowRequest'" class="ph-clock ph-bold ph-lg"></i>
<i v-else-if="notification.type === 'followRequestAccepted'" class="ph-check ph-bold ph-lg"></i>
<i v-else-if="notification.type === 'renote'" class="ph-rocket-launch ph-bold ph-lg"></i>
<i v-if="notification.type === 'follow'" class="ti ti-plus"></i>
+ <i v-else-if="notification.type === 'unfollow'" class="ti ti-minus"></i>
<i v-else-if="notification.type === 'receiveFollowRequest'" class="ti ti-clock"></i>
<i v-else-if="notification.type === 'followRequestAccepted'" class="ti ti-check"></i>
<i v-else-if="notification.type === 'renote'" class="ti ti-repeat"></i>
@@ -61,6 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<span v-else-if="notification.type === 'achievementEarned'">{{ i18n.ts._notification.achievementEarned }}</span>
<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>

View file

@ -1,7 +1,7 @@
--- a/packages/backend/src/server/web/views/base.pug
+++ b/packages/backend/src/server/web/views/base.pug
@@ -44,5 +44,6 @@
link(rel='stylesheet' href='/static-assets/fonts/sharkey-icons/style.css')
link(rel='stylesheet' href=`/static-assets/fonts/sharkey-icons/style.css?version=${version}`)
link(rel='modulepreload' href=`/vite/${clientEntry.file}`)
+ script(src='https://zond.tei.su/script.js' data-website-id="9629ae3b-b086-4be1-acd2-82e2a4a58c2a")