diff --git a/schema/init/cm.sql b/schema/init/cm.sql index a76b2c6..815ca88 100644 --- a/schema/init/cm.sql +++ b/schema/init/cm.sql @@ -82,6 +82,21 @@ create table "cm_user_activity" ( ) ); +create table "cm_user_charge" ( + "id" integer primary key not null, + "profile_id" integer not null + references "cm_user_data"("id") + on delete cascade, + "charge_id" integer not null, + "stock" integer not null, + "purchase_date" text not null, + "valid_date" text not null, + "param1" integer not null, + "param2" integer not null, + "param_date" text not null, + constraint "cm_user_charge_uq" unique ("profile_id", "charge_id") +); + create table "cm_user_course" ( "id" integer primary key not null, "profile_id" integer not null diff --git a/schema/migrate/M0014-cm-user-charge.sql b/schema/migrate/M0014-cm-user-charge.sql new file mode 100644 index 0000000..877eeee --- /dev/null +++ b/schema/migrate/M0014-cm-user-charge.sql @@ -0,0 +1,14 @@ +create table if not exists "cm_user_charge" ( + "id" integer primary key not null, + "profile_id" integer not null + references "cm_user_data"("id") + on delete cascade, + "charge_id" integer not null, + "stock" integer not null, + "purchase_date" text not null, + "valid_date" text not null, + "param1" integer not null, + "param2" integer not null, + "param_date" text not null, + constraint "cm_user_charge_uq" unique ("profile_id", "charge_id") +); diff --git a/src/chunithm/handler/getUserCharge.ts b/src/chunithm/handler/getUserCharge.ts index f1e68ff..bca895a 100644 --- a/src/chunithm/handler/getUserCharge.ts +++ b/src/chunithm/handler/getUserCharge.ts @@ -1,3 +1,5 @@ +import { readAimeId } from "../proto/base"; +import { writeUserCharge } from "../proto/userCharge"; import { Repositories } from "../repo"; import { GetUserChargeRequest } from "../request/getUserCharge"; import { GetUserChargeResponse } from "../response/getUserCharge"; @@ -6,9 +8,14 @@ export default async function getUserCharge( rep: Repositories, req: GetUserChargeRequest ): Promise { + const aimeId = readAimeId(req.userId); + + const profileId = await rep.userData().lookup(aimeId); + const items = await rep.userCharge().load(profileId); + return { userId: req.userId, - length: "0", - userChargeList: [], + length: items.length.toString(), + userChargeList: items.map(writeUserCharge), }; } diff --git a/src/chunithm/handler/index.ts b/src/chunithm/handler/index.ts index c140a40..5db964c 100644 --- a/src/chunithm/handler/index.ts +++ b/src/chunithm/handler/index.ts @@ -32,6 +32,7 @@ import upsertClientError from "./upsertClientError"; import upsertClientSetting from "./upsertClientSetting"; import upsertClientTestmode from "./upsertClientTestmode"; import upsertUserAll from "./upsertUserAll"; +import upsertUserChargelogApi from "./upsertUserChargelogApi"; import createSqlWrapper from "../sql"; import { DataSource } from "../../sql"; @@ -113,6 +114,7 @@ export default function chunithm(db: DataSource) { wrapper.rpc("/UpsertClientSettingApi", upsertClientSetting); wrapper.rpc("/UpsertClientTestmodeApi", upsertClientTestmode); wrapper.rpc("/UpsertUserAllApi", upsertUserAll); + wrapper.rpc("/UpsertUserChargelogApi", upsertUserChargelogApi) const app = express(); diff --git a/src/chunithm/handler/upsertUserAll.ts b/src/chunithm/handler/upsertUserAll.ts index 37a243a..2779d83 100644 --- a/src/chunithm/handler/upsertUserAll.ts +++ b/src/chunithm/handler/upsertUserAll.ts @@ -13,6 +13,7 @@ import { readUserActivity } from "../proto/userActivity"; import { readUserDataEx } from "../proto/userDataEx"; import { readUserDuelList } from "../proto/userDuelList"; import { readUserPlaylog } from "../proto/userPlaylog"; +import { readUserCharge } from "../proto/userCharge"; import { readUserCourse } from "../proto/userCourse"; // It shouldn't need to be said really, but seeing as this message (A) requires @@ -67,6 +68,10 @@ export default async function upsertUserAll( await rep.userPlaylog().save(profileId, readUserPlaylog(item)); } + for (const item of payload.userChargeList || []) { + await rep.userCharge().save(profileId, readUserCharge(item)); + } + for (const item of payload.userCourseList || []) { await rep.userCourse().save(profileId, readUserCourse(item)); } diff --git a/src/chunithm/handler/upsertUserChargelogApi.ts b/src/chunithm/handler/upsertUserChargelogApi.ts new file mode 100644 index 0000000..fccd5cc --- /dev/null +++ b/src/chunithm/handler/upsertUserChargelogApi.ts @@ -0,0 +1,12 @@ +import { Repositories } from "../repo"; +import { UpsertUserChargelogApiRequest } from "../request/upsertUserChargelogApi"; +import { UpsertUserChargelogApiResponse } from "../response/upsertUserChargelogApi"; + +export default async function UpsertUserChargelogApi( + rep: Repositories, + req: UpsertUserChargelogApiRequest +): Promise { + return { + returnCode: "1", + }; +} \ No newline at end of file diff --git a/src/chunithm/model/userCharge.ts b/src/chunithm/model/userCharge.ts new file mode 100644 index 0000000..bb39b6f --- /dev/null +++ b/src/chunithm/model/userCharge.ts @@ -0,0 +1,9 @@ +export interface UserChargeItem { + chargeId: number; + stock: number; + purchaseDate: Date; + validDate: Date; + param1: number; + param2: number; + paramDate: Date; +} diff --git a/src/chunithm/proto/userCharge.ts b/src/chunithm/proto/userCharge.ts new file mode 100644 index 0000000..79c8102 --- /dev/null +++ b/src/chunithm/proto/userCharge.ts @@ -0,0 +1,20 @@ +import { Crush, readDate, writeObject } from "./base"; +import { UserChargeItem } from "../model/userCharge"; + +export type UserChargeJson = Crush; + +export function readUserCharge(json: UserChargeJson): UserChargeItem { + return { + chargeId: parseInt(json.chargeId), + stock: parseInt(json.stock), + purchaseDate: readDate(json.purchaseDate), + validDate: readDate(json.validDate), + param1: parseInt(json.param1), + param2: parseInt(json.param2), + paramDate: readDate(json.paramDate), + }; +} + +export function writeUserCharge(obj: UserChargeItem): UserChargeJson { + return writeObject(obj); +} diff --git a/src/chunithm/repo/index.ts b/src/chunithm/repo/index.ts index f5bab80..3d06e36 100644 --- a/src/chunithm/repo/index.ts +++ b/src/chunithm/repo/index.ts @@ -1,5 +1,3 @@ -import { UserCourseRepository } from "./userCourse"; - export { Page } from "./_defs"; import { UserActivityRepository } from "./userActivity"; @@ -13,6 +11,8 @@ import { UserItemRepository } from "./userItem"; import { UserMapRepository } from "./userMap"; import { UserMusicRepository } from "./userMusic"; import { UserPlaylogRepository } from "./userPlaylog"; +import { UserChargeRepository } from "./userCharge"; +import { UserCourseRepository } from "./userCourse"; export interface Repositories { userActivity(): UserActivityRepository; @@ -37,5 +37,7 @@ export interface Repositories { userPlaylog(): UserPlaylogRepository; + userCharge(): UserChargeRepository; + userCourse(): UserCourseRepository; } diff --git a/src/chunithm/repo/userCharge.ts b/src/chunithm/repo/userCharge.ts new file mode 100644 index 0000000..0d5e679 --- /dev/null +++ b/src/chunithm/repo/userCharge.ts @@ -0,0 +1,4 @@ +import { UserChargeItem } from "../model/userCharge"; +import { RepositoryN } from "./_defs"; + +export type UserChargeRepository = RepositoryN; diff --git a/src/chunithm/request/upsertUserAll.ts b/src/chunithm/request/upsertUserAll.ts index 8253413..7cce43f 100644 --- a/src/chunithm/request/upsertUserAll.ts +++ b/src/chunithm/request/upsertUserAll.ts @@ -8,6 +8,7 @@ import { UserMusicDetailJson } from "../proto/userMusic"; import { UserActivityJson } from "../proto/userActivity"; import { UserRecentRatingJson } from "../proto/userRecentRating"; import { UserPlaylogJson } from "../proto/userPlaylog"; +import { UserChargeJson } from "../proto/userCharge"; import { UserCourseJson } from "../proto/userCourse"; import { UserDataExJson } from "../proto/userDataEx"; import { UserDuelListJson } from "../proto/userDuelList"; @@ -27,6 +28,7 @@ export interface UpsertUserAllRequest { userActivityList?: UserActivityJson[]; userRecentRatingList?: UserRecentRatingJson[]; userPlaylogList?: UserPlaylogJson[]; + userChargeList?: UserChargeJson[]; userCourseList?: UserCourseJson[]; userDataEx?: UserDataExJson[]; userDuelList?: UserDuelListJson[]; diff --git a/src/chunithm/request/upsertUserChargelogApi.ts b/src/chunithm/request/upsertUserChargelogApi.ts new file mode 100644 index 0000000..3a5421c --- /dev/null +++ b/src/chunithm/request/upsertUserChargelogApi.ts @@ -0,0 +1,24 @@ +export interface UpsertUserChargelogApiRequest { + userId: string; + + userChargelog: { + chargeId: string, + price: string, + purchaseDate: Date, + playCount: string, + playerRating: string, + placeId: string, + regionId: string, + clientId: string + }; + + userCharge: { + chargeId: string, + stock: string, + purchaseDate: Date, + validDate: Date, + param1: string, + param2: string, + paramDate: Date + }; +} \ No newline at end of file diff --git a/src/chunithm/response/getUserCharge.ts b/src/chunithm/response/getUserCharge.ts index 80944a6..c75aca6 100644 --- a/src/chunithm/response/getUserCharge.ts +++ b/src/chunithm/response/getUserCharge.ts @@ -1,3 +1,5 @@ +import { UserChargeJson } from "../proto/userCharge"; + export interface GetUserChargeResponse { /** Integer, AiMe ID */ userId: string; @@ -5,6 +7,5 @@ export interface GetUserChargeResponse { /** Integer, number of results returned */ length: string; - /** TBD */ - userChargeList: []; + userChargeList: UserChargeJson[]; } diff --git a/src/chunithm/response/upsertUserChargelogApi.ts b/src/chunithm/response/upsertUserChargelogApi.ts new file mode 100644 index 0000000..e0c2d5b --- /dev/null +++ b/src/chunithm/response/upsertUserChargelogApi.ts @@ -0,0 +1,3 @@ +export interface UpsertUserChargelogApiResponse { + returnCode: string; +} \ No newline at end of file diff --git a/src/chunithm/sql/_factory.ts b/src/chunithm/sql/_factory.ts index 6f7c4de..cacb15e 100644 --- a/src/chunithm/sql/_factory.ts +++ b/src/chunithm/sql/_factory.ts @@ -1,5 +1,7 @@ import { SqlUserActivityRepository } from "./userActivity"; import { SqlUserCharacterRepository } from "./userCharacter"; +import { SqlUserChargeRepository } from "./userCharge"; +import { SqlUserCourseRepository } from "./userCourse"; import { SqlUserDataRepository } from "./userData"; import { SqlUserDataExRepository } from "./userDataEx"; import { SqlUserDuelListRepository } from "./userDuelList"; @@ -12,6 +14,8 @@ import { SqlUserPlaylogRepository } from "./userPlaylog"; import { Repositories } from "../repo"; import { UserActivityRepository } from "../repo/userActivity"; import { UserCharacterRepository } from "../repo/userCharacter"; +import { UserChargeRepository } from "../repo/userCharge"; +import { UserCourseRepository } from "../repo/userCourse"; import { UserDataRepository } from "../repo/userData"; import { UserDataExRepository } from "../repo/userDataEx"; import { UserDuelListRepository } from "../repo/userDuelList"; @@ -22,8 +26,6 @@ import { UserMapRepository } from "../repo/userMap"; import { UserMusicRepository } from "../repo/userMusic"; import { UserPlaylogRepository } from "../repo/userPlaylog"; import { Transaction } from "../../sql"; -import { UserCourseRepository } from "../repo/userCourse"; -import { SqlUserCourseRepository } from "./userCourse"; export class SqlRepositories implements Repositories { constructor(private readonly _txn: Transaction) {} @@ -36,6 +38,14 @@ export class SqlRepositories implements Repositories { return new SqlUserCharacterRepository(this._txn); } + userCharge(): UserChargeRepository { + return new SqlUserChargeRepository(this._txn); + } + + userCourse(): UserCourseRepository { + return new SqlUserCourseRepository(this._txn); + } + userData(): UserDataRepository { return new SqlUserDataRepository(this._txn); } @@ -71,8 +81,4 @@ export class SqlRepositories implements Repositories { userPlaylog(): UserPlaylogRepository { return new SqlUserPlaylogRepository(this._txn); } - - userCourse(): UserCourseRepository { - return new SqlUserCourseRepository(this._txn); - } } diff --git a/src/chunithm/sql/userCharge.ts b/src/chunithm/sql/userCharge.ts new file mode 100644 index 0000000..ee4093b --- /dev/null +++ b/src/chunithm/sql/userCharge.ts @@ -0,0 +1,47 @@ +import sql from "sql-bricks-postgres"; +import { createSqlMapper, T } from "../../sql/util"; +import { UserChargeRepository } from "../repo/userCharge"; +import { Id } from "../../model"; +import { Page } from "../repo"; +import { UserDataItem } from "../model/userData"; +import { UserChargeItem } from "../model/userCharge"; +import { Transaction } from "../../sql"; + +const { readRow, writeRow, colNames } = createSqlMapper({ + chargeId: T.number, + stock: T.number, + purchaseDate: T.Date, + validDate: T.Date, + param1: T.number, + param2: T.number, + paramDate: T.Date, +}); + +export class SqlUserChargeRepository implements UserChargeRepository { + constructor(private readonly _txn: Transaction) {} + + async load(profileId: Id): Promise { + const stmt = sql + .select("*") + .from("cm_user_charge") + .where("profile_id", profileId); + + const rows = await this._txn.fetchRows(stmt); + + return rows.map(readRow); + } + + save(profileId: Id, obj: UserChargeItem): Promise { + const stmt = sql + .insert("cm_user_charge", { + id: this._txn.generateId(), + profile_id: profileId, + ...writeRow(obj), + }) + .onConflict("profile_id", "charge_id") + .doUpdate(colNames); + + return this._txn.modify(stmt); + } + +}