diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 3c7645ec919b491b58cb773245097404d181e01b..b1f484f6b24ac717428f5c655bb1d5af388b8cf4 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -777,6 +777,7 @@ popularPosts: "人気ã®æŠ•ç¨¿" shareWithNote: "ノートã§å…±æœ‰" ads: "広告" expiration: "期é™" +startingperiod: "開始期間" memo: "メモ" priority: "優先度" high: "高" diff --git a/packages/backend/migration/1676438468213-ad3.js b/packages/backend/migration/1676438468213-ad3.js new file mode 100644 index 0000000000000000000000000000000000000000..082bb31325bcacc67fa4c6c687e2ede931deea26 --- /dev/null +++ b/packages/backend/migration/1676438468213-ad3.js @@ -0,0 +1,9 @@ +export class ad1676438468213 { + name = 'ad1676438468213'; + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "ad" ADD "startAt" TIMESTAMP WITH TIME ZONE NOT NULL`); + } + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "role" DROP COLUMN "startAt"`); + } +} diff --git a/packages/backend/src/models/entities/Ad.ts b/packages/backend/src/models/entities/Ad.ts index 36b758f205b6d5395c31b31ef31534b4043d0a54..c87932adb6754a6468b62ef17d19ae7e194935c9 100644 --- a/packages/backend/src/models/entities/Ad.ts +++ b/packages/backend/src/models/entities/Ad.ts @@ -18,6 +18,12 @@ export class Ad { }) public expiresAt: Date; + @Index() + @Column('timestamp with time zone', { + comment: 'The expired date of the Ad.', + }) + public startAt: Date; + @Column('varchar', { length: 32, nullable: false, }) 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 8fcbde591b185a2202415a07dab4c49c90abd9fd..ba128c75a776c2d5054b0481ea2e3c78a21a0bcd 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/create.ts @@ -20,9 +20,10 @@ export const paramDef = { priority: { type: 'string' }, ratio: { type: 'integer' }, expiresAt: { type: 'integer' }, + startAt: { type: 'integer' }, imageUrl: { type: 'string', minLength: 1 }, }, - required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'imageUrl'], + required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startAt', 'imageUrl'], } as const; // eslint-disable-next-line import/no-default-export @@ -39,6 +40,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { id: this.idService.genId(), createdAt: new Date(), expiresAt: new Date(ps.expiresAt), + startAt: new Date(ps.startAt), url: ps.url, imageUrl: ps.imageUrl, priority: ps.priority, diff --git a/packages/backend/src/server/api/endpoints/admin/ad/list.ts b/packages/backend/src/server/api/endpoints/admin/ad/list.ts index 29e245ab95f50f164a71e0ac7e76bc5e8a10e032..905036c40fc96df96233a2882a6b580b970ac4bb 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/list.ts @@ -32,8 +32,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { ) { super(meta, paramDef, async (ps, me) => { const query = this.queryService.makePaginationQuery(this.adsRepository.createQueryBuilder('ad'), ps.sinceId, ps.untilId) - .andWhere('ad.expiresAt > :now', { now: new Date() }); - const ads = await query.take(ps.limit).getMany(); return ads; 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 08e3c96ca960d0c9345d9cbf4642abbc331c28bb..75f6f1d5ad2d1ce72cc0aff0a09e39210c143d0a 100644 --- a/packages/backend/src/server/api/endpoints/admin/ad/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/ad/update.ts @@ -30,8 +30,9 @@ export const paramDef = { priority: { type: 'string' }, ratio: { type: 'integer' }, expiresAt: { type: 'integer' }, + startAt: { type: 'integer' }, }, - required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt'], + required: ['id', 'memo', 'url', 'imageUrl', 'place', 'priority', 'ratio', 'expiresAt', 'startAt'], } as const; // eslint-disable-next-line import/no-default-export @@ -54,6 +55,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { memo: ps.memo, imageUrl: ps.imageUrl, expiresAt: new Date(ps.expiresAt), + startAt: new Date(ps.startAt), }); }); } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 2fa7a09d49af741d141da521b4a0d2c2587d40ef..823c3f72b03ce39a5f046617ef2054947c3ccc2e 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, MoreThan } from 'typeorm'; +import { IsNull, LessThanOrEqual, MoreThan } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; import type { AdsRepository, EmojisRepository, UsersRepository } from '@/models/index.js'; import { MAX_NOTE_TEXT_LENGTH, DB_MAX_NOTE_TEXT_LENGTH } from '@/const.js'; @@ -262,6 +262,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { const ads = await this.adsRepository.find({ where: { expiresAt: MoreThan(new Date()), + startAt: LessThanOrEqual(new Date()), }, }); diff --git a/packages/frontend/src/pages/admin/ads.vue b/packages/frontend/src/pages/admin/ads.vue index 701ec31b65dad8b6540bdcb233f145171538a1b7..88131fce8969b9feb5e364fd584f6be3732a03a4 100644 --- a/packages/frontend/src/pages/admin/ads.vue +++ b/packages/frontend/src/pages/admin/ads.vue @@ -29,6 +29,9 @@ <MkInput v-model="ad.ratio" type="number"> <template #label>{{ i18n.ts.ratio }}</template> </MkInput> + <MkInput v-model="ad.startAt" type="datetime-local"> + <template #label>{{ i18n.ts.startingperiod }}</template> + </MkInput> <MkInput v-model="ad.expiresAt" type="datetime-local"> <template #label>{{ i18n.ts.expiration }}</template> </MkInput> @@ -66,11 +69,14 @@ const localTimeDiff = localTime.getTimezoneOffset() * 60 * 1000; os.api('admin/ad/list').then(adsResponse => { ads = adsResponse.map(r => { - const date = new Date(r.expiresAt); - date.setMilliseconds(date.getMilliseconds() - localTimeDiff); + const exdate = new Date(r.expiresAt); + const stdate = new Date(r.startAt); + exdate.setMilliseconds(exdate.getMilliseconds() - localTimeDiff); + stdate.setMilliseconds(stdate.getMilliseconds() - localTimeDiff); return { ...r, - expiresAt: date.toISOString().slice(0, 16), + expiresAt: exdate.toISOString().slice(0, 16), + startAt: stdate.toISOString().slice(0, 16), }; }); }); @@ -85,6 +91,7 @@ function add() { url: '', imageUrl: null, expiresAt: null, + startAt: null, }); } @@ -106,11 +113,13 @@ function save(ad) { os.apiWithDialog('admin/ad/create', { ...ad, expiresAt: new Date(ad.expiresAt).getTime(), + startAt: new Date(ad.startAt).getTime(), }); } else { os.apiWithDialog('admin/ad/update', { ...ad, expiresAt: new Date(ad.expiresAt).getTime(), + startAt: new Date(ad.startAt).getTime(), }); } }