summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/web
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server/web')
-rw-r--r--packages/backend/src/server/web/ClientServerService.ts68
-rw-r--r--packages/backend/src/server/web/boot.js2
-rw-r--r--packages/backend/src/server/web/style.css8
-rw-r--r--packages/backend/src/server/web/style.embed.css10
-rw-r--r--packages/backend/src/server/web/views/announcement.pug21
-rw-r--r--packages/backend/src/server/web/views/base.pug6
6 files changed, 98 insertions, 17 deletions
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index 42f9b104ff..e59314bf55 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -30,6 +30,7 @@ import type {
EndedPollNotificationQueue,
InboxQueue,
ObjectStorageQueue,
+ RelationshipQueue,
SystemQueue,
UserWebhookDeliverQueue,
SystemWebhookDeliverQueue,
@@ -42,13 +43,26 @@ import { MetaEntityService } from '@/core/entities/MetaEntityService.js';
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
-import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, ReversiGamesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
+import type {
+ AnnouncementsRepository,
+ ChannelsRepository,
+ ClipsRepository,
+ FlashsRepository,
+ GalleryPostsRepository,
+ MiMeta,
+ NotesRepository,
+ PagesRepository,
+ ReversiGamesRepository,
+ UserProfilesRepository,
+ UsersRepository,
+} from '@/models/_.js';
import type Logger from '@/logger.js';
import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js';
import { bindThis } from '@/decorators.js';
import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
import { RoleService } from '@/core/RoleService.js';
import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js';
+import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
import { FeedService } from './FeedService.js';
import { UrlPreviewService } from './UrlPreviewService.js';
import { ClientLoggerService } from './ClientLoggerService.js';
@@ -103,6 +117,9 @@ export class ClientServerService {
@Inject(DI.reversiGamesRepository)
private reversiGamesRepository: ReversiGamesRepository,
+ @Inject(DI.announcementsRepository)
+ private announcementsRepository: AnnouncementsRepository,
+
private flashEntityService: FlashEntityService,
private userEntityService: UserEntityService,
private noteEntityService: NoteEntityService,
@@ -112,6 +129,7 @@ export class ClientServerService {
private clipEntityService: ClipEntityService,
private channelEntityService: ChannelEntityService,
private reversiGameEntityService: ReversiGameEntityService,
+ private announcementEntityService: AnnouncementEntityService,
private urlPreviewService: UrlPreviewService,
private feedService: FeedService,
private roleService: RoleService,
@@ -122,6 +140,7 @@ export class ClientServerService {
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
@Inject('queue:inbox') public inboxQueue: InboxQueue,
@Inject('queue:db') public dbQueue: DbQueue,
+ @Inject('queue:relationship') public relationshipQueue: RelationshipQueue,
@Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue,
@Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue,
@Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue,
@@ -253,6 +272,7 @@ export class ClientServerService {
this.deliverQueue,
this.inboxQueue,
this.dbQueue,
+ this.relationshipQueue,
this.objectStorageQueue,
this.userWebhookDeliverQueue,
this.systemWebhookDeliverQueue,
@@ -561,7 +581,7 @@ export class ClientServerService {
}
});
- //#region SSR (for crawlers)
+ //#region SSR
// User
fastify.get<{ Params: { user: string; sub?: string; } }>('/@:user/:sub?', async (request, reply) => {
const { username, host } = Acct.parse(request.params.user);
@@ -586,11 +606,20 @@ export class ClientServerService {
reply.header('X-Robots-Tag', 'noimageai');
reply.header('X-Robots-Tag', 'noai');
}
+
+ const _user = await this.userEntityService.pack(user, null, {
+ schema: 'UserDetailed',
+ userProfile: profile,
+ });
+
return await reply.view('user', {
user, profile, me,
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
sub: request.params.sub,
...await this.generateCommonPugData(this.meta),
+ clientCtx: htmlSafeJsonStringify({
+ user: _user,
+ }),
});
} else {
// リモートユーザーなので
@@ -620,12 +649,15 @@ export class ClientServerService {
fastify.get<{ Params: { note: string; } }>('/notes/:note', async (request, reply) => {
vary(reply.raw, 'Accept');
- const note = await this.notesRepository.findOneBy({
- id: request.params.note,
- visibility: In(['public', 'home']),
+ const note = await this.notesRepository.findOne({
+ where: {
+ id: request.params.note,
+ visibility: In(['public', 'home']),
+ },
+ relations: ['user'],
});
- if (note) {
+ if (note && !note.user!.requireSigninToViewContents) {
const _note = await this.noteEntityService.pack(note);
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: note.userId });
reply.header('Cache-Control', 'public, max-age=15');
@@ -640,6 +672,9 @@ export class ClientServerService {
// TODO: Let locale changeable by instance setting
summary: getNoteSummary(_note),
...await this.generateCommonPugData(this.meta),
+ clientCtx: htmlSafeJsonStringify({
+ note: _note,
+ }),
});
} else {
return await renderBase(reply);
@@ -728,6 +763,9 @@ export class ClientServerService {
profile,
avatarUrl: _clip.user.avatarUrl,
...await this.generateCommonPugData(this.meta),
+ clientCtx: htmlSafeJsonStringify({
+ clip: _clip,
+ }),
});
} else {
return await renderBase(reply);
@@ -792,6 +830,24 @@ export class ClientServerService {
return await renderBase(reply);
}
});
+
+ // 個別お知らせページ
+ fastify.get<{ Params: { announcementId: string; } }>('/announcements/:announcementId', async (request, reply) => {
+ const announcement = await this.announcementsRepository.findOneBy({
+ id: request.params.announcementId,
+ });
+
+ if (announcement) {
+ const _announcement = await this.announcementEntityService.pack(announcement);
+ reply.header('Cache-Control', 'public, max-age=3600');
+ return await reply.view('announcement', {
+ announcement: _announcement,
+ ...await this.generateCommonPugData(this.meta),
+ });
+ } else {
+ return await renderBase(reply);
+ }
+ });
//#endregion
//#region noindex pages
diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js
index ad92480c1c..bf83340bde 100644
--- a/packages/backend/src/server/web/boot.js
+++ b/packages/backend/src/server/web/boot.js
@@ -108,7 +108,7 @@
}
for (const [k, v] of Object.entries(themeProps)) {
if (k.startsWith('font')) continue;
- document.documentElement.style.setProperty(`--${k}`, v.toString());
+ document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString());
// HTMLの theme-color 適用
if (k === 'htmlThemeColor') {
diff --git a/packages/backend/src/server/web/style.css b/packages/backend/src/server/web/style.css
index 1cd9cadecf..8094a0f6de 100644
--- a/packages/backend/src/server/web/style.css
+++ b/packages/backend/src/server/web/style.css
@@ -5,8 +5,8 @@
*/
html {
- background-color: var(--bg);
- color: var(--fg);
+ background-color: var(--MI_THEME-bg);
+ color: var(--MI_THEME-fg);
}
#splash {
@@ -17,7 +17,7 @@ html {
width: 100vw;
height: 100vh;
cursor: wait;
- background-color: var(--bg);
+ background-color: var(--MI_THEME-bg);
opacity: 1;
transition: opacity 0.5s ease;
}
@@ -45,7 +45,7 @@ html {
width: 28px;
height: 28px;
transform: translateY(80px);
- color: var(--accent);
+ color: var(--MI_THEME-accent);
}
#splashSpinner > .spinner {
diff --git a/packages/backend/src/server/web/style.embed.css b/packages/backend/src/server/web/style.embed.css
index a7b110d80a..5e8786cc4e 100644
--- a/packages/backend/src/server/web/style.embed.css
+++ b/packages/backend/src/server/web/style.embed.css
@@ -5,8 +5,8 @@
*/
html {
- background-color: var(--bg);
- color: var(--fg);
+ background-color: var(--MI_THEME-bg);
+ color: var(--MI_THEME-fg);
}
html.embed {
@@ -24,7 +24,7 @@ html.embed {
width: 100vw;
height: 100vh;
cursor: wait;
- background-color: var(--bg);
+ background-color: var(--MI_THEME-bg);
opacity: 1;
transition: opacity 0.5s ease;
}
@@ -33,7 +33,7 @@ html.embed #splash {
box-sizing: border-box;
min-height: 300px;
border-radius: var(--radius, 12px);
- border: 1px solid var(--divider, #e8e8e8);
+ border: 1px solid var(--MI_THEME-divider, #e8e8e8);
}
html.embed.norounded #splash {
@@ -67,7 +67,7 @@ html.embed.noborder #splash {
width: 28px;
height: 28px;
transform: translateY(70px);
- color: var(--accent);
+ color: var(--MI_THEME-accent);
}
#splashSpinner > .spinner {
diff --git a/packages/backend/src/server/web/views/announcement.pug b/packages/backend/src/server/web/views/announcement.pug
new file mode 100644
index 0000000000..7a4052e8a4
--- /dev/null
+++ b/packages/backend/src/server/web/views/announcement.pug
@@ -0,0 +1,21 @@
+extends ./base
+
+block vars
+ - const title = announcement.title;
+ - const description = announcement.text.length > 100 ? announcement.text.slice(0, 100) + '…' : announcement.text;
+ - const url = `${config.url}/announcements/${announcement.id}`;
+
+block title
+ = `${title} | ${instanceName}`
+
+block desc
+ meta(name='description' content=description)
+
+block og
+ meta(property='og:type' content='article')
+ meta(property='og:title' content= title)
+ meta(property='og:description' content= description)
+ meta(property='og:url' content= url)
+ if announcement.imageUrl
+ meta(property='og:image' content=announcement.imageUrl)
+ meta(property='twitter:card' content='summary_large_image')
diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug
index 84c4832802..f57dbbbf4e 100644
--- a/packages/backend/src/server/web/views/base.pug
+++ b/packages/backend/src/server/web/views/base.pug
@@ -2,6 +2,7 @@ block vars
block loadClientEntry
- const entry = config.frontendEntry;
+ - const baseUrl = config.url;
doctype html
@@ -36,7 +37,7 @@ html
link(rel='icon' href= icon || '/favicon.ico')
link(rel='apple-touch-icon' href= appleTouchIcon || '/apple-touch-icon.png')
link(rel='manifest' href='/manifest.json')
- link(rel='search' type='application/opensearchdescription+xml' title=(title || "Sharkey") href=`${url}/opensearch.xml`)
+ link(rel='search' type='application/opensearchdescription+xml' title=(title || "Sharkey") href=`${baseUrl}/opensearch.xml`)
link(rel='prefetch' href=serverErrorImageUrl)
link(rel='prefetch' href=infoImageUrl)
link(rel='prefetch' href=notFoundImageUrl)
@@ -79,6 +80,9 @@ html
script(type='application/json' id='misskey_meta' data-generated-at=now)
!= metaJson
+ script(type='application/json' id='misskey_clientCtx' data-generated-at=now)
+ != clientCtx
+
script
include ../boot.js