From 3c6175d95952c6f0e2d55e7e0064cbc1cd297fdd Mon Sep 17 00:00:00 2001 From: nenohi Date: Sat, 8 Jul 2023 08:56:11 +0900 Subject: [PATCH] =?UTF-8?q?=E5=BA=83=E5=91=8A=E3=81=AE=E6=9B=9C=E6=97=A5?= =?UTF-8?q?=E3=82=92=E8=A8=AD=E5=AE=9A=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=20(#10095)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 曜日選択できるように * ラベル選択でもチェックが変更されるように * adを参照しないといけないかも * smallint -> integer * 異物混入だったので取りだし * タイムゾーン指定(Date2つ使うのなんか違和感 * 未テスト * これにすると出てこないかも * UIチョット変更 * UI変更 fix bug * 畳むように修正 * dayofweek->dayOfWeek * マイグレ時にnot null,default設定してるのでnullable:falseでよさそう * コメントの記載 * Update packages/backend/src/server/api/endpoints/meta.ts Co-authored-by: Acid Chicken (硫酸鶏) --------- Co-authored-by: Acid Chicken (硫酸鶏) --- locales/ja-JP.yml | 1 + .../backend/migration/1677054292210-ad4.js | 9 +++++++++ packages/backend/src/models/entities/Ad.ts | 5 ++++- .../server/api/endpoints/admin/ad/create.ts | 4 +++- .../server/api/endpoints/admin/ad/update.ts | 4 +++- .../backend/src/server/api/endpoints/meta.ts | 20 +++++++++++-------- packages/frontend/src/pages/admin/ads.vue | 19 ++++++++++++++++++ 7 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 packages/backend/migration/1677054292210-ad4.js diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 0b2817e1ad..51122655b5 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1451,6 +1451,7 @@ _ad: back: "戻る" reduceFrequencyOfThisAd: "この広告の表示頻度を下げる" hide: "表示しない" + timezoneinfo: "曜日はサーバーのタイムゾーンを元に指定されます。" _forgotPassword: enterEmail: "アカウントに登録したメールアドレスを入力してください。そのアドレス宛てに、パスワードリセット用のリンクが送信されます。" diff --git a/packages/backend/migration/1677054292210-ad4.js b/packages/backend/migration/1677054292210-ad4.js new file mode 100644 index 0000000000..48499319b4 --- /dev/null +++ b/packages/backend/migration/1677054292210-ad4.js @@ -0,0 +1,9 @@ +export class ad1677054292210 { + name = 'ad1677054292210'; + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "ad" ADD "dayOfWeek" integer NOT NULL Default 0`); + } + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "ad" DROP COLUMN "dayOfWeek"`); + } +} diff --git a/packages/backend/src/models/entities/Ad.ts b/packages/backend/src/models/entities/Ad.ts index 56baf863ca..a496a6d276 100644 --- a/packages/backend/src/models/entities/Ad.ts +++ b/packages/backend/src/models/entities/Ad.ts @@ -55,7 +55,10 @@ export class Ad { length: 8192, nullable: false, }) public memo: string; - + @Column('integer', { + default: 0, nullable: false, + }) + public dayOfWeek: number; constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/server/api/endpoints/admin/ad/create.ts b/packages/backend/src/server/api/endpoints/admin/ad/create.ts index 917242db3f..757030839e 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts @@ -22,8 +22,9 @@ export const paramDef = { expiresAt: { type: 'integer' }, startsAt: { type: 'integer' }, imageUrl: { type: 'string', minLength: 1 }, + dayOfWeek: { type: 'integer' }, }, - required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl'], + required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl', 'dayOfWeek'], } as const; // eslint-disable-next-line import/no-default-export @@ -41,6 +42,7 @@ export default class extends Endpoint { createdAt: new Date(), expiresAt: new Date(ps.expiresAt), startsAt: new Date(ps.startsAt), + dayOfWeek: ps.dayOfWeek, url: ps.url, imageUrl: ps.imageUrl, priority: ps.priority, diff --git a/packages/backend/src/server/api/endpoints/admin/ad/update.ts b/packages/backend/src/server/api/endpoints/admin/ad/update.ts index dbab7e9d4f..70082290ba 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts @@ -31,8 +31,9 @@ export const paramDef = { ratio: { type: 'integer' }, expiresAt: { type: 'integer' }, startsAt: { type: 'integer' }, + dayOfWeek: { type: 'integer' }, }, - required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt'], + required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'dayOfWeek'], } as const; // eslint-disable-next-line import/no-default-export @@ -56,6 +57,7 @@ export default class extends Endpoint { imageUrl: ps.imageUrl, expiresAt: new Date(ps.expiresAt), startsAt: new Date(ps.startsAt), + dayOfWeek: ps.dayOfWeek, }); }); } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 6ef5f0d5c8..915a1e54f8 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -1,4 +1,4 @@ -import { IsNull, LessThanOrEqual, MoreThan } from 'typeorm'; +import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; import JSON5 from 'json5'; import type { AdsRepository, UsersRepository } from '@/models/index.js'; @@ -263,13 +263,16 @@ export default class extends Endpoint { super(meta, paramDef, async (ps, me) => { const instance = await this.metaService.fetch(true); - const ads = await this.adsRepository.find({ - where: { - expiresAt: MoreThan(new Date()), - startsAt: LessThanOrEqual(new Date()), - }, - }); - + const ads = await this.adsRepository.createQueryBuilder("ads") + .where('ads.expiresAt > :now', { now: new Date() }) + .andWhere('ads.startsAt <= :now', { now: new Date() }) + .andWhere(new Brackets(qb => { + // 曜日のビットフラグを確認する + qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() }) + .orWhere('ads.dayOfWeek = 0'); + })) + .getMany(); + const response: any = { maintainerName: instance.maintainerName, maintainerEmail: instance.maintainerEmail, @@ -311,6 +314,7 @@ export default class extends Endpoint { place: ad.place, ratio: ad.ratio, imageUrl: ad.imageUrl, + dayOfWeek: ad.dayOfWeek, })), enableEmail: instance.enableEmail, enableServiceWorker: instance.enableServiceWorker, diff --git a/packages/frontend/src/pages/admin/ads.vue b/packages/frontend/src/pages/admin/ads.vue index 2c9e18b0bf..9a5bd88b2e 100644 --- a/packages/frontend/src/pages/admin/ads.vue +++ b/packages/frontend/src/pages/admin/ads.vue @@ -36,6 +36,16 @@ + + + + {{ i18n.ts._ad.timezoneinfo }} +
+ + +
+
+
@@ -59,6 +69,7 @@ import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkTextarea from '@/components/MkTextarea.vue'; import MkRadios from '@/components/MkRadios.vue'; +import MkFolder from '@/components/MkFolder.vue'; import FormSplit from '@/components/form/split.vue'; import * as os from '@/os'; import { i18n } from '@/i18n'; @@ -69,6 +80,7 @@ let ads: any[] = $ref([]); // ISO形式はTZがUTCになってしまうので、TZ分ずらして時間を初期化 const localTime = new Date(); const localTimeDiff = localTime.getTimezoneOffset() * 60 * 1000; +const daysOfWeek: string[] = [i18n.ts._weekday.sunday, i18n.ts._weekday.monday, i18n.ts._weekday.tuesday, i18n.ts._weekday.wednesday, i18n.ts._weekday.thursday, i18n.ts._weekday.friday, i18n.ts._weekday.saturday]; os.api('admin/ad/list').then(adsResponse => { ads = adsResponse.map(r => { @@ -84,6 +96,11 @@ os.api('admin/ad/list').then(adsResponse => { }); }); +// 選択された曜日(index)のビットフラグを操作する +function toggleDayOfWeek(ad, index) { + ad.dayOfWeek ^= 1 << index; +} + function add() { ads.unshift({ id: null, @@ -95,6 +112,7 @@ function add() { imageUrl: null, expiresAt: null, startsAt: null, + dayOfWeek: 0, }); } @@ -105,6 +123,7 @@ function remove(ad) { }).then(({ canceled }) => { if (canceled) return; ads = ads.filter(x => x !== ad); + if (ad.id == null) return; os.apiWithDialog('admin/ad/delete', { id: ad.id, });