yes
This commit is contained in:
parent
00e4f522ab
commit
37a33d8a73
24 changed files with 1233 additions and 202 deletions
|
|
@ -1,13 +1,21 @@
|
||||||
FROM node:22-alpine AS pnpm_base
|
FROM node:22-alpine AS pnpm_base
|
||||||
RUN npm install --global pnpm@10;
|
RUN npm install --global pnpm@10;
|
||||||
|
|
||||||
|
FROM pnpm_base AS deps
|
||||||
|
|
||||||
|
COPY ./package.json ./pnpm-lock.yaml ./pnpm-workspace.yaml /src/
|
||||||
|
WORKDIR /src
|
||||||
|
RUN pnpm install --frozen-lockfile;
|
||||||
|
|
||||||
FROM pnpm_base AS builder
|
FROM pnpm_base AS builder
|
||||||
|
|
||||||
COPY . /src
|
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
RUN pnpm install --frozen-lockfile && pnpm run build;
|
COPY --from=deps /src/node_modules /src/node_modules
|
||||||
|
COPY . /src
|
||||||
|
|
||||||
FROM node:22-alpine
|
RUN pnpm run build;
|
||||||
|
|
||||||
|
FROM pnpm_base
|
||||||
|
|
||||||
COPY --from=builder /src/dist /dist
|
COPY --from=builder /src/dist /dist
|
||||||
COPY ./run.sh /bin/run.sh
|
COPY ./run.sh /bin/run.sh
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
apis/OpenapiOtherApi.ts
|
apis/OpenapiOtherApi.ts
|
||||||
apis/index.ts
|
apis/index.ts
|
||||||
index.ts
|
index.ts
|
||||||
|
models/ChangeDisplayName200Response.ts
|
||||||
|
models/ChangeDisplayName400Response.ts
|
||||||
|
models/ChangeDisplayNameRequest.ts
|
||||||
models/ChatTest200Response.ts
|
models/ChatTest200Response.ts
|
||||||
models/ChatTest200ResponsePayload.ts
|
models/ChatTest200ResponsePayload.ts
|
||||||
models/DisableOtp200Response.ts
|
models/DisableOtp200Response.ts
|
||||||
|
|
@ -20,7 +23,9 @@ models/GetUser404Response.ts
|
||||||
models/GetUserUserParameter.ts
|
models/GetUserUserParameter.ts
|
||||||
models/GuestLogin200Response.ts
|
models/GuestLogin200Response.ts
|
||||||
models/GuestLogin200ResponsePayload.ts
|
models/GuestLogin200ResponsePayload.ts
|
||||||
|
models/GuestLogin400Response.ts
|
||||||
models/GuestLogin500Response.ts
|
models/GuestLogin500Response.ts
|
||||||
|
models/GuestLoginRequest.ts
|
||||||
models/Login200Response.ts
|
models/Login200Response.ts
|
||||||
models/Login202Response.ts
|
models/Login202Response.ts
|
||||||
models/Login202ResponsePayload.ts
|
models/Login202ResponsePayload.ts
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@
|
||||||
|
|
||||||
import * as runtime from '../runtime';
|
import * as runtime from '../runtime';
|
||||||
import type {
|
import type {
|
||||||
|
ChangeDisplayName200Response,
|
||||||
|
ChangeDisplayName400Response,
|
||||||
|
ChangeDisplayNameRequest,
|
||||||
ChatTest200Response,
|
ChatTest200Response,
|
||||||
DisableOtp200Response,
|
DisableOtp200Response,
|
||||||
DisableOtp400Response,
|
DisableOtp400Response,
|
||||||
|
|
@ -28,7 +31,9 @@ import type {
|
||||||
GetUser404Response,
|
GetUser404Response,
|
||||||
GetUserUserParameter,
|
GetUserUserParameter,
|
||||||
GuestLogin200Response,
|
GuestLogin200Response,
|
||||||
|
GuestLogin400Response,
|
||||||
GuestLogin500Response,
|
GuestLogin500Response,
|
||||||
|
GuestLoginRequest,
|
||||||
Login200Response,
|
Login200Response,
|
||||||
Login202Response,
|
Login202Response,
|
||||||
Login400Response,
|
Login400Response,
|
||||||
|
|
@ -49,6 +54,12 @@ import type {
|
||||||
StatusOtp500Response,
|
StatusOtp500Response,
|
||||||
} from '../models/index';
|
} from '../models/index';
|
||||||
import {
|
import {
|
||||||
|
ChangeDisplayName200ResponseFromJSON,
|
||||||
|
ChangeDisplayName200ResponseToJSON,
|
||||||
|
ChangeDisplayName400ResponseFromJSON,
|
||||||
|
ChangeDisplayName400ResponseToJSON,
|
||||||
|
ChangeDisplayNameRequestFromJSON,
|
||||||
|
ChangeDisplayNameRequestToJSON,
|
||||||
ChatTest200ResponseFromJSON,
|
ChatTest200ResponseFromJSON,
|
||||||
ChatTest200ResponseToJSON,
|
ChatTest200ResponseToJSON,
|
||||||
DisableOtp200ResponseFromJSON,
|
DisableOtp200ResponseFromJSON,
|
||||||
|
|
@ -75,8 +86,12 @@ import {
|
||||||
GetUserUserParameterToJSON,
|
GetUserUserParameterToJSON,
|
||||||
GuestLogin200ResponseFromJSON,
|
GuestLogin200ResponseFromJSON,
|
||||||
GuestLogin200ResponseToJSON,
|
GuestLogin200ResponseToJSON,
|
||||||
|
GuestLogin400ResponseFromJSON,
|
||||||
|
GuestLogin400ResponseToJSON,
|
||||||
GuestLogin500ResponseFromJSON,
|
GuestLogin500ResponseFromJSON,
|
||||||
GuestLogin500ResponseToJSON,
|
GuestLogin500ResponseToJSON,
|
||||||
|
GuestLoginRequestFromJSON,
|
||||||
|
GuestLoginRequestToJSON,
|
||||||
Login200ResponseFromJSON,
|
Login200ResponseFromJSON,
|
||||||
Login200ResponseToJSON,
|
Login200ResponseToJSON,
|
||||||
Login202ResponseFromJSON,
|
Login202ResponseFromJSON,
|
||||||
|
|
@ -115,10 +130,18 @@ import {
|
||||||
StatusOtp500ResponseToJSON,
|
StatusOtp500ResponseToJSON,
|
||||||
} from '../models/index';
|
} from '../models/index';
|
||||||
|
|
||||||
|
export interface ChangeDisplayNameOperationRequest {
|
||||||
|
changeDisplayNameRequest: ChangeDisplayNameRequest;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GetUserRequest {
|
export interface GetUserRequest {
|
||||||
user: GetUserUserParameter;
|
user: GetUserUserParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GuestLoginOperationRequest {
|
||||||
|
guestLoginRequest?: GuestLoginRequest;
|
||||||
|
}
|
||||||
|
|
||||||
export interface LoginOperationRequest {
|
export interface LoginOperationRequest {
|
||||||
loginRequest: LoginRequest;
|
loginRequest: LoginRequest;
|
||||||
}
|
}
|
||||||
|
|
@ -136,6 +159,62 @@ export interface SigninRequest {
|
||||||
*/
|
*/
|
||||||
export class OpenapiOtherApi extends runtime.BaseAPI {
|
export class OpenapiOtherApi extends runtime.BaseAPI {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
async changeDisplayNameRaw(requestParameters: ChangeDisplayNameOperationRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ChangeDisplayName200Response | ChangeDisplayName400Response | DisableOtp401Response>> {
|
||||||
|
if (requestParameters['changeDisplayNameRequest'] == null) {
|
||||||
|
throw new runtime.RequiredError(
|
||||||
|
'changeDisplayNameRequest',
|
||||||
|
'Required parameter "changeDisplayNameRequest" was null or undefined when calling changeDisplayName().'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParameters: any = {};
|
||||||
|
|
||||||
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
headerParameters['Content-Type'] = 'application/json';
|
||||||
|
|
||||||
|
|
||||||
|
let urlPath = `/api/user/changeDisplayName`;
|
||||||
|
|
||||||
|
const response = await this.request({
|
||||||
|
path: urlPath,
|
||||||
|
method: 'PUT',
|
||||||
|
headers: headerParameters,
|
||||||
|
query: queryParameters,
|
||||||
|
body: ChangeDisplayNameRequestToJSON(requestParameters['changeDisplayNameRequest']),
|
||||||
|
}, initOverrides);
|
||||||
|
|
||||||
|
// CHANGED: Handle all status codes defined in the OpenAPI spec, not just 2xx responses
|
||||||
|
// This allows typed access to error responses (4xx, 5xx) and other status codes.
|
||||||
|
// The code routes responses based on the actual HTTP status code and returns
|
||||||
|
// appropriately typed ApiResponse wrappers for each status code.
|
||||||
|
if (response.status === 200) {
|
||||||
|
// Object response for status 200
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => ChangeDisplayName200ResponseFromJSON(jsonValue));
|
||||||
|
}
|
||||||
|
if (response.status === 400) {
|
||||||
|
// Object response for status 400
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => ChangeDisplayName400ResponseFromJSON(jsonValue));
|
||||||
|
}
|
||||||
|
if (response.status === 401) {
|
||||||
|
// Object response for status 401
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => DisableOtp401ResponseFromJSON(jsonValue));
|
||||||
|
}
|
||||||
|
// CHANGED: Throw error if status code is not handled by any of the defined responses
|
||||||
|
// This ensures all code paths return a value and provides clear error messages for unexpected status codes
|
||||||
|
// Only throw if responses were defined but none matched the actual status code
|
||||||
|
throw new runtime.ResponseError(response, `Unexpected status code: ${response.status}. Expected one of: 200, 400, 401`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
async changeDisplayName(requestParameters: ChangeDisplayNameOperationRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<ChangeDisplayName200Response | ChangeDisplayName400Response | DisableOtp401Response> {
|
||||||
|
const response = await this.changeDisplayNameRaw(requestParameters, initOverrides);
|
||||||
|
return await response.value();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
async chatTestRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ChatTest200Response | StatusOtp401Response>> {
|
async chatTestRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ChatTest200Response | StatusOtp401Response>> {
|
||||||
|
|
@ -334,11 +413,13 @@ export class OpenapiOtherApi extends runtime.BaseAPI {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
async guestLoginRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<GuestLogin200Response | GuestLogin500Response>> {
|
async guestLoginRaw(requestParameters: GuestLoginOperationRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<GuestLogin200Response | GuestLogin400Response | GuestLogin500Response>> {
|
||||||
const queryParameters: any = {};
|
const queryParameters: any = {};
|
||||||
|
|
||||||
const headerParameters: runtime.HTTPHeaders = {};
|
const headerParameters: runtime.HTTPHeaders = {};
|
||||||
|
|
||||||
|
headerParameters['Content-Type'] = 'application/json';
|
||||||
|
|
||||||
|
|
||||||
let urlPath = `/api/auth/guest`;
|
let urlPath = `/api/auth/guest`;
|
||||||
|
|
||||||
|
|
@ -347,6 +428,7 @@ export class OpenapiOtherApi extends runtime.BaseAPI {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: headerParameters,
|
headers: headerParameters,
|
||||||
query: queryParameters,
|
query: queryParameters,
|
||||||
|
body: GuestLoginRequestToJSON(requestParameters['guestLoginRequest']),
|
||||||
}, initOverrides);
|
}, initOverrides);
|
||||||
|
|
||||||
// CHANGED: Handle all status codes defined in the OpenAPI spec, not just 2xx responses
|
// CHANGED: Handle all status codes defined in the OpenAPI spec, not just 2xx responses
|
||||||
|
|
@ -357,6 +439,10 @@ export class OpenapiOtherApi extends runtime.BaseAPI {
|
||||||
// Object response for status 200
|
// Object response for status 200
|
||||||
return new runtime.JSONApiResponse(response, (jsonValue) => GuestLogin200ResponseFromJSON(jsonValue));
|
return new runtime.JSONApiResponse(response, (jsonValue) => GuestLogin200ResponseFromJSON(jsonValue));
|
||||||
}
|
}
|
||||||
|
if (response.status === 400) {
|
||||||
|
// Object response for status 400
|
||||||
|
return new runtime.JSONApiResponse(response, (jsonValue) => GuestLogin400ResponseFromJSON(jsonValue));
|
||||||
|
}
|
||||||
if (response.status === 500) {
|
if (response.status === 500) {
|
||||||
// Object response for status 500
|
// Object response for status 500
|
||||||
return new runtime.JSONApiResponse(response, (jsonValue) => GuestLogin500ResponseFromJSON(jsonValue));
|
return new runtime.JSONApiResponse(response, (jsonValue) => GuestLogin500ResponseFromJSON(jsonValue));
|
||||||
|
|
@ -364,13 +450,13 @@ export class OpenapiOtherApi extends runtime.BaseAPI {
|
||||||
// CHANGED: Throw error if status code is not handled by any of the defined responses
|
// CHANGED: Throw error if status code is not handled by any of the defined responses
|
||||||
// This ensures all code paths return a value and provides clear error messages for unexpected status codes
|
// This ensures all code paths return a value and provides clear error messages for unexpected status codes
|
||||||
// Only throw if responses were defined but none matched the actual status code
|
// Only throw if responses were defined but none matched the actual status code
|
||||||
throw new runtime.ResponseError(response, `Unexpected status code: ${response.status}. Expected one of: 200, 500`);
|
throw new runtime.ResponseError(response, `Unexpected status code: ${response.status}. Expected one of: 200, 400, 500`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
async guestLogin(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<GuestLogin200Response | GuestLogin500Response> {
|
async guestLogin(requestParameters: GuestLoginOperationRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<GuestLogin200Response | GuestLogin400Response | GuestLogin500Response> {
|
||||||
const response = await this.guestLoginRaw(initOverrides);
|
const response = await this.guestLoginRaw(requestParameters, initOverrides);
|
||||||
return await response.value();
|
return await response.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* @fastify/swagger
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 9.6.1
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface ChangeDisplayName200Response
|
||||||
|
*/
|
||||||
|
export interface ChangeDisplayName200Response {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ChangeDisplayName200Response
|
||||||
|
*/
|
||||||
|
kind: ChangeDisplayName200ResponseKindEnum;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ChangeDisplayName200Response
|
||||||
|
*/
|
||||||
|
msg: ChangeDisplayName200ResponseMsgEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const ChangeDisplayName200ResponseKindEnum = {
|
||||||
|
Success: 'success'
|
||||||
|
} as const;
|
||||||
|
export type ChangeDisplayName200ResponseKindEnum = typeof ChangeDisplayName200ResponseKindEnum[keyof typeof ChangeDisplayName200ResponseKindEnum];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const ChangeDisplayName200ResponseMsgEnum = {
|
||||||
|
ChangeDisplayNameSuccess: 'changeDisplayName.success'
|
||||||
|
} as const;
|
||||||
|
export type ChangeDisplayName200ResponseMsgEnum = typeof ChangeDisplayName200ResponseMsgEnum[keyof typeof ChangeDisplayName200ResponseMsgEnum];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the ChangeDisplayName200Response interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfChangeDisplayName200Response(value: object): value is ChangeDisplayName200Response {
|
||||||
|
if (!('kind' in value) || value['kind'] === undefined) return false;
|
||||||
|
if (!('msg' in value) || value['msg'] === undefined) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayName200ResponseFromJSON(json: any): ChangeDisplayName200Response {
|
||||||
|
return ChangeDisplayName200ResponseFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayName200ResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): ChangeDisplayName200Response {
|
||||||
|
if (json == null) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'kind': json['kind'],
|
||||||
|
'msg': json['msg'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayName200ResponseToJSON(json: any): ChangeDisplayName200Response {
|
||||||
|
return ChangeDisplayName200ResponseToJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayName200ResponseToJSONTyped(value?: ChangeDisplayName200Response | null, ignoreDiscriminator: boolean = false): any {
|
||||||
|
if (value == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
'kind': value['kind'],
|
||||||
|
'msg': value['msg'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* @fastify/swagger
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 9.6.1
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface ChangeDisplayName400Response
|
||||||
|
*/
|
||||||
|
export interface ChangeDisplayName400Response {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ChangeDisplayName400Response
|
||||||
|
*/
|
||||||
|
kind: ChangeDisplayName400ResponseKindEnum;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ChangeDisplayName400Response
|
||||||
|
*/
|
||||||
|
msg: ChangeDisplayName400ResponseMsgEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const ChangeDisplayName400ResponseKindEnum = {
|
||||||
|
Failure: 'failure'
|
||||||
|
} as const;
|
||||||
|
export type ChangeDisplayName400ResponseKindEnum = typeof ChangeDisplayName400ResponseKindEnum[keyof typeof ChangeDisplayName400ResponseKindEnum];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const ChangeDisplayName400ResponseMsgEnum = {
|
||||||
|
ChangeDisplayNameAlreadyExist: 'changeDisplayName.alreadyExist',
|
||||||
|
ChangeDisplayNameInvalid: 'changeDisplayName.invalid'
|
||||||
|
} as const;
|
||||||
|
export type ChangeDisplayName400ResponseMsgEnum = typeof ChangeDisplayName400ResponseMsgEnum[keyof typeof ChangeDisplayName400ResponseMsgEnum];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the ChangeDisplayName400Response interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfChangeDisplayName400Response(value: object): value is ChangeDisplayName400Response {
|
||||||
|
if (!('kind' in value) || value['kind'] === undefined) return false;
|
||||||
|
if (!('msg' in value) || value['msg'] === undefined) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayName400ResponseFromJSON(json: any): ChangeDisplayName400Response {
|
||||||
|
return ChangeDisplayName400ResponseFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayName400ResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): ChangeDisplayName400Response {
|
||||||
|
if (json == null) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'kind': json['kind'],
|
||||||
|
'msg': json['msg'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayName400ResponseToJSON(json: any): ChangeDisplayName400Response {
|
||||||
|
return ChangeDisplayName400ResponseToJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayName400ResponseToJSONTyped(value?: ChangeDisplayName400Response | null, ignoreDiscriminator: boolean = false): any {
|
||||||
|
if (value == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
'kind': value['kind'],
|
||||||
|
'msg': value['msg'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* @fastify/swagger
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 9.6.1
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface ChangeDisplayNameRequest
|
||||||
|
*/
|
||||||
|
export interface ChangeDisplayNameRequest {
|
||||||
|
/**
|
||||||
|
* New Display Name
|
||||||
|
* @type {string}
|
||||||
|
* @memberof ChangeDisplayNameRequest
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the ChangeDisplayNameRequest interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfChangeDisplayNameRequest(value: object): value is ChangeDisplayNameRequest {
|
||||||
|
if (!('name' in value) || value['name'] === undefined) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayNameRequestFromJSON(json: any): ChangeDisplayNameRequest {
|
||||||
|
return ChangeDisplayNameRequestFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayNameRequestFromJSONTyped(json: any, ignoreDiscriminator: boolean): ChangeDisplayNameRequest {
|
||||||
|
if (json == null) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'name': json['name'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayNameRequestToJSON(json: any): ChangeDisplayNameRequest {
|
||||||
|
return ChangeDisplayNameRequestToJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeDisplayNameRequestToJSONTyped(value?: ChangeDisplayNameRequest | null, ignoreDiscriminator: boolean = false): any {
|
||||||
|
if (value == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
'name': value['name'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
93
frontend/src/api/generated/models/GuestLogin400Response.ts
Normal file
93
frontend/src/api/generated/models/GuestLogin400Response.ts
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* @fastify/swagger
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 9.6.1
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface GuestLogin400Response
|
||||||
|
*/
|
||||||
|
export interface GuestLogin400Response {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof GuestLogin400Response
|
||||||
|
*/
|
||||||
|
kind: GuestLogin400ResponseKindEnum;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof GuestLogin400Response
|
||||||
|
*/
|
||||||
|
msg: GuestLogin400ResponseMsgEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const GuestLogin400ResponseKindEnum = {
|
||||||
|
Failed: 'failed'
|
||||||
|
} as const;
|
||||||
|
export type GuestLogin400ResponseKindEnum = typeof GuestLogin400ResponseKindEnum[keyof typeof GuestLogin400ResponseKindEnum];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const GuestLogin400ResponseMsgEnum = {
|
||||||
|
GuestLoginFailedInvalid: 'guestLogin.failed.invalid'
|
||||||
|
} as const;
|
||||||
|
export type GuestLogin400ResponseMsgEnum = typeof GuestLogin400ResponseMsgEnum[keyof typeof GuestLogin400ResponseMsgEnum];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the GuestLogin400Response interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfGuestLogin400Response(value: object): value is GuestLogin400Response {
|
||||||
|
if (!('kind' in value) || value['kind'] === undefined) return false;
|
||||||
|
if (!('msg' in value) || value['msg'] === undefined) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GuestLogin400ResponseFromJSON(json: any): GuestLogin400Response {
|
||||||
|
return GuestLogin400ResponseFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GuestLogin400ResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): GuestLogin400Response {
|
||||||
|
if (json == null) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'kind': json['kind'],
|
||||||
|
'msg': json['msg'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GuestLogin400ResponseToJSON(json: any): GuestLogin400Response {
|
||||||
|
return GuestLogin400ResponseToJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GuestLogin400ResponseToJSONTyped(value?: GuestLogin400Response | null, ignoreDiscriminator: boolean = false): any {
|
||||||
|
if (value == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
'kind': value['kind'],
|
||||||
|
'msg': value['msg'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
65
frontend/src/api/generated/models/GuestLoginRequest.ts
Normal file
65
frontend/src/api/generated/models/GuestLoginRequest.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* @fastify/swagger
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* The version of the OpenAPI document: 9.6.1
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||||
|
* https://openapi-generator.tech
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { mapValues } from '../runtime';
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface GuestLoginRequest
|
||||||
|
*/
|
||||||
|
export interface GuestLoginRequest {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @memberof GuestLoginRequest
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given object implements the GuestLoginRequest interface.
|
||||||
|
*/
|
||||||
|
export function instanceOfGuestLoginRequest(value: object): value is GuestLoginRequest {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GuestLoginRequestFromJSON(json: any): GuestLoginRequest {
|
||||||
|
return GuestLoginRequestFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GuestLoginRequestFromJSONTyped(json: any, ignoreDiscriminator: boolean): GuestLoginRequest {
|
||||||
|
if (json == null) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
|
||||||
|
'name': json['name'] == null ? undefined : json['name'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GuestLoginRequestToJSON(json: any): GuestLoginRequest {
|
||||||
|
return GuestLoginRequestToJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GuestLoginRequestToJSONTyped(value?: GuestLoginRequest | null, ignoreDiscriminator: boolean = false): any {
|
||||||
|
if (value == null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
'name': value['name'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
export * from './ChangeDisplayName200Response';
|
||||||
|
export * from './ChangeDisplayName400Response';
|
||||||
|
export * from './ChangeDisplayNameRequest';
|
||||||
export * from './ChatTest200Response';
|
export * from './ChatTest200Response';
|
||||||
export * from './ChatTest200ResponsePayload';
|
export * from './ChatTest200ResponsePayload';
|
||||||
export * from './DisableOtp200Response';
|
export * from './DisableOtp200Response';
|
||||||
|
|
@ -19,7 +22,9 @@ export * from './GetUser404Response';
|
||||||
export * from './GetUserUserParameter';
|
export * from './GetUserUserParameter';
|
||||||
export * from './GuestLogin200Response';
|
export * from './GuestLogin200Response';
|
||||||
export * from './GuestLogin200ResponsePayload';
|
export * from './GuestLogin200ResponsePayload';
|
||||||
|
export * from './GuestLogin400Response';
|
||||||
export * from './GuestLogin500Response';
|
export * from './GuestLogin500Response';
|
||||||
|
export * from './GuestLoginRequest';
|
||||||
export * from './Login200Response';
|
export * from './Login200Response';
|
||||||
export * from './Login202Response';
|
export * from './Login202Response';
|
||||||
export * from './Login202ResponsePayload';
|
export * from './Login202ResponsePayload';
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ export type User = {
|
||||||
name: string;
|
name: string;
|
||||||
selfInfo?: {
|
selfInfo?: {
|
||||||
loginName?: string;
|
loginName?: string;
|
||||||
provider_id?: string;
|
providerId?: string;
|
||||||
provider_user?: string;
|
providerUser?: string;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ async function handleLogin(
|
||||||
document.querySelector<HTMLButtonElement>("#bGuestLogin");
|
document.querySelector<HTMLButtonElement>("#bGuestLogin");
|
||||||
bLoginAsGuest?.addEventListener("click", async () => {
|
bLoginAsGuest?.addEventListener("click", async () => {
|
||||||
try {
|
try {
|
||||||
const res = await client.guestLogin();
|
const res = await client.guestLogin({ guestLoginRequest: { name: undefined } });
|
||||||
switch (res.kind) {
|
switch (res.kind) {
|
||||||
case "success": {
|
case "success": {
|
||||||
Cookie.set("token", res.payload.token, {
|
Cookie.set("token", res.payload.token, {
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,33 @@
|
||||||
<span class="text-red-600"> You can't change anything here </span>
|
<span class="text-red-600"> You can't change anything here </span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-1 text-gray-700 rounded-sm border-2 outline-lime-100">
|
||||||
|
<label class="inline font-medium mb-1 text-gray-700">AccountType: </label>
|
||||||
|
<span id="accountType" class="font-medium"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Login Name -->
|
<!-- Login Name -->
|
||||||
<div id="loginNameWrapper" class="py-2">
|
<div id="loginNameWrapper" class="py-2" hidden>
|
||||||
<label class="block font-medium mb-1 text-gray-700">Login Name</label>
|
<label class="block font-medium mb-1 text-gray-700">Login Name</label>
|
||||||
<div id="loginNameBox" class="font-medium mb-1 text-gray-700 rounded-sm border-2 outline-lime-100"></div>
|
<div id="loginNameBox" class="font-medium mb-1 text-gray-700 rounded-sm border-2 outline-lime-100"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Login Name -->
|
||||||
|
<div id="providerWrapper" class="py-2 mb-1 border-2 border-green-400 rounded-sm" hidden>
|
||||||
|
<span class="py-2 mb-1 text-gray-700 text-lg">Provider</span>
|
||||||
|
<div class="flex items-center justify-center gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block font-medium mb-1 text-gray-700">Name</label>
|
||||||
|
<div id="providerNameBox"
|
||||||
|
class="font-medium mb-1 text-gray-700"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block font-medium mb-1 text-gray-700">User</label>
|
||||||
|
<div id="providerUserBox"
|
||||||
|
class="font-medium mb-1 text-gray-700"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Display Name -->
|
<!-- Display Name -->
|
||||||
<div id="displayNameWrapper" class="py-2">
|
<div id="displayNameWrapper" class="py-2">
|
||||||
<label class="block font-medium mb-1 text-gray-700">Display Name</label>
|
<label class="block font-medium mb-1 text-gray-700">Display Name</label>
|
||||||
|
|
@ -35,7 +56,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- TOTP -->
|
<!-- TOTP -->
|
||||||
<div class="border rounded p-4">
|
<div class="border rounded p-4" id="totpWrapper">
|
||||||
<h2 class="font-semibold text-lg mb-2">Two-Factor Authentication (TOTP)</h2>
|
<h2 class="font-semibold text-lg mb-2">Two-Factor Authentication (TOTP)</h2>
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { addRoute, navigateTo, setTitle } from "@app/routing";
|
import { addRoute, handleRoute, navigateTo, setTitle } from "@app/routing";
|
||||||
import { showError } from "@app/toast";
|
import { showError, showSuccess } from "@app/toast";
|
||||||
import page from "./profile.html?raw";
|
import page from "./profile.html?raw";
|
||||||
import { updateUser } from "@app/auth";
|
import { updateUser } from "@app/auth";
|
||||||
import { isNullish } from "@app/utils";
|
import { isNullish } from "@app/utils";
|
||||||
|
|
@ -38,9 +38,16 @@ export async function renderOAuth2QRCode(
|
||||||
});
|
});
|
||||||
canvas.style.width = "";
|
canvas.style.width = "";
|
||||||
canvas.style.height = "";
|
canvas.style.height = "";
|
||||||
}
|
function removeBgColor(...elem: HTMLElement[]) {
|
||||||
|
for (let e of elem) {
|
||||||
|
for (let c of e.classList.values()) {
|
||||||
|
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
||||||
|
e.classList.remove(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function route(url: string, _args: { [k: string]: string }) {
|
async function route(url: string, _args: { [k: string]: string }) {
|
||||||
setTitle("Edit Profile");
|
setTitle("Edit Profile");
|
||||||
return {
|
return {
|
||||||
html: page,
|
html: page,
|
||||||
|
|
@ -90,11 +97,15 @@ async function route(url: string, _args: { [k: string]: string }) {
|
||||||
let passwordButton =
|
let passwordButton =
|
||||||
app.querySelector<HTMLButtonElement>("#passwordButton")!;
|
app.querySelector<HTMLButtonElement>("#passwordButton")!;
|
||||||
|
|
||||||
if (!isNullish(user.selfInfo?.loginName))
|
let providerWrapper =
|
||||||
loginNameBox.innerText = user.selfInfo?.loginName;
|
app.querySelector<HTMLDivElement>("#providerWrapper")!;
|
||||||
else
|
let providerNameBox =
|
||||||
loginNameBox.innerHTML =
|
app.querySelector<HTMLDivElement>("#providerNameBox")!;
|
||||||
'<span class="text-red-600 font-bold mb-1">You don\'t have a login name</span>';
|
let providerUserBox =
|
||||||
|
app.querySelector<HTMLDivElement>("#providerUserBox")!;
|
||||||
|
|
||||||
|
let accountTypeBox =
|
||||||
|
app.querySelector<HTMLDivElement>("#accountType")!;
|
||||||
displayNameBox.value = user.name;
|
displayNameBox.value = user.name;
|
||||||
|
|
||||||
guestBox.hidden = !user.guest;
|
guestBox.hidden = !user.guest;
|
||||||
|
|
@ -118,7 +129,17 @@ async function route(url: string, _args: { [k: string]: string }) {
|
||||||
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
||||||
passwordButton.classList.remove(c);
|
passwordButton.classList.remove(c);
|
||||||
}
|
}
|
||||||
passwordButton.disabled = true;
|
let totpWrapper = app.querySelector<HTMLDivElement>("#totpWrapper")!;
|
||||||
|
|
||||||
|
if (user.guest) {
|
||||||
|
removeBgColor(
|
||||||
|
passwordButton,
|
||||||
|
displayNameButton,
|
||||||
|
enableBtn,
|
||||||
|
disableBtn,
|
||||||
|
showSecretBtn,
|
||||||
|
);
|
||||||
|
|
||||||
passwordButton.classList.add(
|
passwordButton.classList.add(
|
||||||
"bg-gray-700",
|
"bg-gray-700",
|
||||||
"hover:bg-gray-700",
|
"hover:bg-gray-700",
|
||||||
|
|
@ -127,29 +148,11 @@ async function route(url: string, _args: { [k: string]: string }) {
|
||||||
passwordBox.disabled = true;
|
passwordBox.disabled = true;
|
||||||
passwordBox.classList.add("color-white");
|
passwordBox.classList.add("color-white");
|
||||||
|
|
||||||
for (let c of displayNameButton.classList.values()) {
|
|
||||||
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
|
||||||
displayNameButton.classList.remove(c);
|
|
||||||
}
|
|
||||||
displayNameButton.disabled = true;
|
displayNameButton.disabled = true;
|
||||||
displayNameButton.classList.add("bg-gray-700");
|
displayNameButton.classList.add("bg-gray-700", "color-white");
|
||||||
displayNameButton.classList.add("color-white");
|
|
||||||
|
|
||||||
displayNameBox.disabled = true;
|
displayNameBox.disabled = true;
|
||||||
displayNameBox.classList.add("color-white");
|
displayNameBox.classList.add("color-white");
|
||||||
|
|
||||||
for (let c of enableBtn.classList.values()) {
|
|
||||||
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
|
||||||
enableBtn.classList.remove(c);
|
|
||||||
}
|
|
||||||
for (let c of disableBtn.classList.values()) {
|
|
||||||
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
|
||||||
disableBtn.classList.remove(c);
|
|
||||||
}
|
|
||||||
for (let c of showSecretBtn.classList.values()) {
|
|
||||||
if (c.startsWith("bg-") || c.startsWith("hover:bg-"))
|
|
||||||
showSecretBtn.classList.remove(c);
|
|
||||||
}
|
|
||||||
enableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
enableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
disableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
disableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
showSecretBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
showSecretBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
|
@ -157,6 +160,34 @@ async function route(url: string, _args: { [k: string]: string }) {
|
||||||
enableBtn.disabled = true;
|
enableBtn.disabled = true;
|
||||||
disableBtn.disabled = true;
|
disableBtn.disabled = true;
|
||||||
showSecretBtn.disabled = true;
|
showSecretBtn.disabled = true;
|
||||||
|
|
||||||
|
accountTypeBox.innerText = "Guest";
|
||||||
|
} else if (!isNullish(user.selfInfo?.loginName)) {
|
||||||
|
loginNameWrapper.hidden = false;
|
||||||
|
loginNameBox.innerText = user.selfInfo.loginName;
|
||||||
|
|
||||||
|
accountTypeBox.innerText = "Normal";
|
||||||
|
} else if (
|
||||||
|
!isNullish(user.selfInfo?.providerId) &&
|
||||||
|
!isNullish(user.selfInfo?.providerUser)
|
||||||
|
) {
|
||||||
|
providerWrapper.hidden = false;
|
||||||
|
providerNameBox.innerText = user.selfInfo.providerId;
|
||||||
|
providerUserBox.innerText = user.selfInfo.providerUser;
|
||||||
|
|
||||||
|
enableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
disableBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
showSecretBtn.classList.add("bg-gray-700", "hover:bg-gray-700");
|
||||||
|
|
||||||
|
enableBtn.disabled = true;
|
||||||
|
disableBtn.disabled = true;
|
||||||
|
showSecretBtn.disabled = true;
|
||||||
|
|
||||||
|
removeBgColor(enableBtn, disableBtn, showSecretBtn);
|
||||||
|
passwordWrapper.hidden = true;
|
||||||
|
totpWrapper.hidden = true;
|
||||||
|
|
||||||
|
accountTypeBox.innerText = "Provider";
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Update UI ----
|
// ---- Update UI ----
|
||||||
|
|
@ -204,10 +235,22 @@ async function route(url: string, _args: { [k: string]: string }) {
|
||||||
secretBox.classList.toggle("hidden");
|
secretBox.classList.toggle("hidden");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
displayNameButton.onclick = async () => {
|
||||||
|
let req = await client.changeDisplayName({
|
||||||
|
changeDisplayNameRequest: { name: displayNameBox.value },
|
||||||
|
});
|
||||||
|
if (req.kind === "success") {
|
||||||
|
showSuccess("Successfully changed display name");
|
||||||
|
handleRoute();
|
||||||
|
} else {
|
||||||
|
showError(`Failed to update: ${req.msg}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Initialize UI state
|
// Initialize UI state
|
||||||
refreshTotpUI();
|
refreshTotpUI();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
addRoute("/profile", route);
|
addRoute("/profile", route);
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Project Transcendance {
|
||||||
Table user {
|
Table user {
|
||||||
id text [PK, not null]
|
id text [PK, not null]
|
||||||
login text [unique]
|
login text [unique]
|
||||||
name text [not null]
|
name text [not null, unique]
|
||||||
password text [null, Note: "If password is NULL, this means that the user is created through OAUTH2 or guest login"]
|
password text [null, Note: "If password is NULL, this means that the user is created through OAUTH2 or guest login"]
|
||||||
otp text [null, Note: "If otp is NULL, then the user didn't configure 2FA"]
|
otp text [null, Note: "If otp is NULL, then the user didn't configure 2FA"]
|
||||||
guest integer [not null, default: 0]
|
guest integer [not null, default: 0]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
CREATE TABLE IF NOT EXISTS user (
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
id TEXT PRIMARY KEY NOT NULL,
|
id TEXT PRIMARY KEY NOT NULL,
|
||||||
login TEXT UNIQUE,
|
login TEXT UNIQUE,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL UNIQUE,
|
||||||
password TEXT,
|
password TEXT,
|
||||||
otp TEXT,
|
otp TEXT,
|
||||||
guest INTEGER NOT NULL DEFAULT 0,
|
guest INTEGER NOT NULL DEFAULT 0,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { Otp } from '@shared/auth';
|
||||||
import { isNullish } from '@shared/utils';
|
import { isNullish } from '@shared/utils';
|
||||||
import * as bcrypt from 'bcrypt';
|
import * as bcrypt from 'bcrypt';
|
||||||
import { UUID, newUUID } from '@shared/utils/uuid';
|
import { UUID, newUUID } from '@shared/utils/uuid';
|
||||||
|
import { SqliteError } from 'better-sqlite3';
|
||||||
|
|
||||||
// never use this directly
|
// never use this directly
|
||||||
|
|
||||||
|
|
@ -20,6 +21,10 @@ export interface IUserDb extends Database {
|
||||||
getAllUserFromProvider(provider: string): User[] | undefined,
|
getAllUserFromProvider(provider: string): User[] | undefined,
|
||||||
getAllUsers(this: IUserDb): User[] | undefined,
|
getAllUsers(this: IUserDb): User[] | undefined,
|
||||||
|
|
||||||
|
|
||||||
|
updateDisplayName(id: UserId, new_name: string): boolean,
|
||||||
|
|
||||||
|
getUserFromDisplayName(name: string): User | undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UserImpl: Omit<IUserDb, keyof Database> = {
|
export const UserImpl: Omit<IUserDb, keyof Database> = {
|
||||||
|
|
@ -159,6 +164,24 @@ export const UserImpl: Omit<IUserDb, keyof Database> = {
|
||||||
const req = this.prepare('SELECT * FROM user WHERE oauth2 = @oauth2').get({ oauth2: `${provider}:${unique}` }) as Partial<User> | undefined;
|
const req = this.prepare('SELECT * FROM user WHERE oauth2 = @oauth2').get({ oauth2: `${provider}:${unique}` }) as Partial<User> | undefined;
|
||||||
return userFromRow(req);
|
return userFromRow(req);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateDisplayName(this: IUserDb, id: UserId, new_name: string): boolean {
|
||||||
|
try {
|
||||||
|
this.prepare('UPDATE OR FAIL user SET name = @new_name WHERE id = @id').run({ id, new_name });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e instanceof SqliteError) {
|
||||||
|
if (e.code === 'SQLITE_CONSTRAINT_UNIQUE') return false;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getUserFromDisplayName(this: IUserDb, name: string) {
|
||||||
|
const res = this.prepare('SELECT * FROM user WHERE name = @name LIMIT 1').get({ name }) as User | undefined;
|
||||||
|
return userFromRow(res);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserId = UUID;
|
export type UserId = UUID;
|
||||||
|
|
@ -170,7 +193,7 @@ export type User = {
|
||||||
readonly password?: string;
|
readonly password?: string;
|
||||||
readonly otp?: string;
|
readonly otp?: string;
|
||||||
readonly guest: boolean;
|
readonly guest: boolean;
|
||||||
// will be split/merged from the `provider` column
|
// will be split/merged from the `oauth2` column
|
||||||
readonly provider_name?: string;
|
readonly provider_name?: string;
|
||||||
readonly provider_unique?: string;
|
readonly provider_unique?: string;
|
||||||
};
|
};
|
||||||
|
|
@ -207,7 +230,7 @@ async function hashPassword(
|
||||||
*
|
*
|
||||||
* @returns The user if it exists, undefined otherwise
|
* @returns The user if it exists, undefined otherwise
|
||||||
*/
|
*/
|
||||||
export function userFromRow(row?: Partial<Omit<User, 'provider_name' | 'provider_unique'> & { provider?: string }>): User | undefined {
|
export function userFromRow(row?: Partial<Omit<User, 'provider_name' | 'provider_unique'> & { oauth2?: string }>): User | undefined {
|
||||||
if (isNullish(row)) return undefined;
|
if (isNullish(row)) return undefined;
|
||||||
if (isNullish(row.id)) return undefined;
|
if (isNullish(row.id)) return undefined;
|
||||||
if (isNullish(row.name)) return undefined;
|
if (isNullish(row.name)) return undefined;
|
||||||
|
|
@ -216,9 +239,9 @@ export function userFromRow(row?: Partial<Omit<User, 'provider_name' | 'provider
|
||||||
let provider_name = undefined;
|
let provider_name = undefined;
|
||||||
let provider_unique = undefined;
|
let provider_unique = undefined;
|
||||||
|
|
||||||
if (row.provider) {
|
if (row.oauth2) {
|
||||||
const splitted = row.provider.split(':', 1);
|
const splitted = row.oauth2.split(/:(.*)/);
|
||||||
if (splitted.length != 2) { return undefined; }
|
if (splitted.length != 3) { return undefined; }
|
||||||
provider_name = splitted[0];
|
provider_name = splitted[0];
|
||||||
provider_unique = splitted[1];
|
provider_unique = splitted[1];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,20 @@
|
||||||
"/api/auth/guest": {
|
"/api/auth/guest": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "guestLogin",
|
"operationId": "guestLogin",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Default Response",
|
"description": "Default Response",
|
||||||
|
|
@ -370,6 +384,32 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Default Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"enum": [
|
||||||
|
"failed"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"enum": [
|
||||||
|
"guestLogin.failed.invalid"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"500": {
|
"500": {
|
||||||
"description": "Default Response",
|
"description": "Default Response",
|
||||||
"content": {
|
"content": {
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,95 @@
|
||||||
import { FastifyPluginAsync } from 'fastify';
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
|
|
||||||
import { Type } from 'typebox';
|
import { Static, Type } from 'typebox';
|
||||||
import { typeResponse, isNullish, MakeStaticResponse } from '@shared/utils';
|
import { typeResponse, isNullish, MakeStaticResponse } from '@shared/utils';
|
||||||
|
|
||||||
export const GuestLoginRes = {
|
export const GuestLoginRes = {
|
||||||
'500': typeResponse('failed', ['guestLogin.failed.generic.unknown', 'guestLogin.failed.generic.error']),
|
'500': typeResponse('failed', [
|
||||||
|
'guestLogin.failed.generic.unknown',
|
||||||
|
'guestLogin.failed.generic.error',
|
||||||
|
]),
|
||||||
'200': typeResponse('success', 'guestLogin.success', {
|
'200': typeResponse('success', 'guestLogin.success', {
|
||||||
token: Type.String({
|
token: Type.String({
|
||||||
description: 'JWT that represent a logged in user',
|
description: 'JWT that represent a logged in user',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
'400': typeResponse('failed', 'guestLogin.failed.invalid'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GuestLoginRes = MakeStaticResponse<typeof GuestLoginRes>;
|
export type GuestLoginRes = MakeStaticResponse<typeof GuestLoginRes>;
|
||||||
|
|
||||||
|
export const GuestLoginReq = Type.Object({
|
||||||
|
name: Type.Optional(Type.String()),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type GuestLoginReq = Static<typeof GuestLoginReq>;
|
||||||
|
|
||||||
const getRandomFromList = (list: string[]): string => {
|
const getRandomFromList = (list: string[]): string => {
|
||||||
return list[Math.floor(Math.random() * list.length)];
|
return list[Math.floor(Math.random() * list.length)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const USERNAME_CHECK: RegExp = /^[a-zA-Z_0-9]+$/;
|
||||||
|
|
||||||
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||||
void _opts;
|
void _opts;
|
||||||
fastify.post<{ Body: null, Reply: GuestLoginRes }>(
|
fastify.post<{ Body: GuestLoginReq; Reply: GuestLoginRes }>(
|
||||||
'/api/auth/guest',
|
'/api/auth/guest',
|
||||||
{ schema: { response: GuestLoginRes, operationId: 'guestLogin' } },
|
{
|
||||||
|
schema: {
|
||||||
|
body: GuestLoginReq,
|
||||||
|
response: GuestLoginRes,
|
||||||
|
operationId: 'guestLogin',
|
||||||
|
},
|
||||||
|
},
|
||||||
async function(req, res) {
|
async function(req, res) {
|
||||||
void req;
|
void req;
|
||||||
void res;
|
void res;
|
||||||
try {
|
try {
|
||||||
console.log('DEBUG ----- guest login backend');
|
let user_name: string | undefined = req.body?.name;
|
||||||
const adjective = getRandomFromList(fastify.words.adjectives);
|
if (isNullish(user_name)) {
|
||||||
|
const adjective = getRandomFromList(
|
||||||
|
fastify.words.adjectives,
|
||||||
|
);
|
||||||
const noun = getRandomFromList(fastify.words.nouns);
|
const noun = getRandomFromList(fastify.words.nouns);
|
||||||
|
user_name = `${adjective}${noun}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (user_name.length < 4 || user_name.length > 26) {
|
||||||
|
return res.makeResponse(
|
||||||
|
400,
|
||||||
|
'failed',
|
||||||
|
'guestLogin.failed.invalid',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!USERNAME_CHECK.test(user_name)) {
|
||||||
|
return res.makeResponse(
|
||||||
|
400,
|
||||||
|
'failed',
|
||||||
|
'guestLogin.failed.invalid',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
user_name = `g_${user_name}`;
|
||||||
|
}
|
||||||
|
|
||||||
const user = await this.db.createGuestUser(`${adjective} ${noun}`);
|
const orig = user_name;
|
||||||
|
let i = 0;
|
||||||
|
while (
|
||||||
|
this.db.getUserFromDisplayName(user_name) !== undefined &&
|
||||||
|
i++ < 5
|
||||||
|
) {
|
||||||
|
user_name = `${orig}${Date.now() % 1000}`;
|
||||||
|
}
|
||||||
|
if (this.db.getUserFromDisplayName(user_name) !== undefined) {
|
||||||
|
user_name = `${orig}${Date.now()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await this.db.createGuestUser(user_name);
|
||||||
if (isNullish(user)) {
|
if (isNullish(user)) {
|
||||||
return res.makeResponse(500, 'failed', 'guestLogin.failed.generic.unknown');
|
return res.makeResponse(
|
||||||
|
500,
|
||||||
|
'failed',
|
||||||
|
'guestLogin.failed.generic.unknown',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return res.makeResponse(200, 'success', 'guestLogin.success', {
|
return res.makeResponse(200, 'success', 'guestLogin.success', {
|
||||||
token: this.signJwt('auth', user.id.toString()),
|
token: this.signJwt('auth', user.id.toString()),
|
||||||
|
|
@ -41,7 +97,11 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||||
}
|
}
|
||||||
catch (e: unknown) {
|
catch (e: unknown) {
|
||||||
fastify.log.error(e);
|
fastify.log.error(e);
|
||||||
return res.makeResponse(500, 'failed', 'guestLogin.failed.generic.error');
|
return res.makeResponse(
|
||||||
|
500,
|
||||||
|
'failed',
|
||||||
|
'guestLogin.failed.generic.error',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,23 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||||
const result = await creq.getCode();
|
const result = await creq.getCode();
|
||||||
|
|
||||||
const userinfo = await provider.getUserInfo(result);
|
const userinfo = await provider.getUserInfo(result);
|
||||||
|
|
||||||
|
|
||||||
let u = this.db.getOauth2User(provider.display_name, userinfo.unique_id);
|
let u = this.db.getOauth2User(provider.display_name, userinfo.unique_id);
|
||||||
if (isNullish(u)) {
|
if (isNullish(u)) {
|
||||||
u = await this.db.createOauth2User(userinfo.name, provider.display_name, userinfo.unique_id);
|
let user_name = userinfo.name;
|
||||||
|
const orig = user_name;
|
||||||
|
let i = 0;
|
||||||
|
while (
|
||||||
|
this.db.getUserFromDisplayName(user_name) !== undefined &&
|
||||||
|
i++ < 100
|
||||||
|
) {
|
||||||
|
user_name = `${orig}${Date.now() % 1000}`;
|
||||||
|
}
|
||||||
|
if (this.db.getUserFromDisplayName(user_name) !== undefined) {
|
||||||
|
user_name = `${orig}${Date.now()}`;
|
||||||
|
}
|
||||||
|
u = await this.db.createOauth2User(user_name, provider.display_name, userinfo.unique_id);
|
||||||
}
|
}
|
||||||
if (isNullish(u)) {
|
if (isNullish(u)) {
|
||||||
return res.code(500).send('failed to fetch or create user...');
|
return res.code(500).send('failed to fetch or create user...');
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,19 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||||
// password is good too !
|
// password is good too !
|
||||||
|
|
||||||
if (this.db.getUserFromLoginName(name) !== undefined) { return res.makeResponse(400, 'failed', 'signin.failed.username.existing'); }
|
if (this.db.getUserFromLoginName(name) !== undefined) { return res.makeResponse(400, 'failed', 'signin.failed.username.existing'); }
|
||||||
const u = await this.db.createUser(name, name, password);
|
let user_name = name;
|
||||||
|
const orig = user_name;
|
||||||
|
let i = 0;
|
||||||
|
while (
|
||||||
|
this.db.getUserFromDisplayName(user_name) !== undefined &&
|
||||||
|
i++ < 100
|
||||||
|
) {
|
||||||
|
user_name = `${orig}${Date.now() % 1000}`;
|
||||||
|
}
|
||||||
|
if (this.db.getUserFromDisplayName(user_name) !== undefined) {
|
||||||
|
user_name = `${orig}${Date.now()}`;
|
||||||
|
}
|
||||||
|
const u = await this.db.createUser(name, user_name, password);
|
||||||
if (isNullish(u)) { return res.makeResponse(500, 'failed', 'signin.failed.generic'); }
|
if (isNullish(u)) { return res.makeResponse(500, 'failed', 'signin.failed.generic'); }
|
||||||
|
|
||||||
// every check has been passed, they are now logged in, using this token to say who they are...
|
// every check has been passed, they are now logged in, using this token to say who they are...
|
||||||
|
|
|
||||||
151
src/openapi.json
151
src/openapi.json
|
|
@ -352,6 +352,20 @@
|
||||||
"/api/auth/guest": {
|
"/api/auth/guest": {
|
||||||
"post": {
|
"post": {
|
||||||
"operationId": "guestLogin",
|
"operationId": "guestLogin",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Default Response",
|
"description": "Default Response",
|
||||||
|
|
@ -392,6 +406,32 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Default Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"enum": [
|
||||||
|
"failed"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"enum": [
|
||||||
|
"guestLogin.failed.invalid"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"500": {
|
"500": {
|
||||||
"description": "Default Response",
|
"description": "Default Response",
|
||||||
"content": {
|
"content": {
|
||||||
|
|
@ -1057,6 +1097,117 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/user/changeDisplayName": {
|
||||||
|
"put": {
|
||||||
|
"operationId": "changeDisplayName",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "New Display Name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Default Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"enum": [
|
||||||
|
"success"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"enum": [
|
||||||
|
"changeDisplayName.success"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Default Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"enum": [
|
||||||
|
"failure"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"enum": [
|
||||||
|
"changeDisplayName.alreadyExist",
|
||||||
|
"changeDisplayName.invalid"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Default Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"enum": [
|
||||||
|
"notLoggedIn"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"enum": [
|
||||||
|
"auth.noCookie",
|
||||||
|
"auth.invalidKind",
|
||||||
|
"auth.noUser",
|
||||||
|
"auth.invalid"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"openapi_other"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/user/info/{user}": {
|
"/api/user/info/{user}": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "getUser",
|
"operationId": "getUser",
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,114 @@
|
||||||
"schemas": {}
|
"schemas": {}
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
|
"/api/user/changeDisplayName": {
|
||||||
|
"put": {
|
||||||
|
"operationId": "changeDisplayName",
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "New Display Name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Default Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"enum": [
|
||||||
|
"success"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"enum": [
|
||||||
|
"changeDisplayName.success"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Default Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"enum": [
|
||||||
|
"failure"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"enum": [
|
||||||
|
"changeDisplayName.alreadyExist",
|
||||||
|
"changeDisplayName.invalid"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Default Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"msg"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"enum": [
|
||||||
|
"notLoggedIn"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"enum": [
|
||||||
|
"auth.noCookie",
|
||||||
|
"auth.invalidKind",
|
||||||
|
"auth.noUser",
|
||||||
|
"auth.invalid"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/user/info/{user}": {
|
"/api/user/info/{user}": {
|
||||||
"get": {
|
"get": {
|
||||||
"operationId": "getUser",
|
"operationId": "getUser",
|
||||||
|
|
|
||||||
44
src/user/src/routes/changeDisplayName.ts
Normal file
44
src/user/src/routes/changeDisplayName.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { FastifyPluginAsync } from 'fastify';
|
||||||
|
|
||||||
|
import { Static, Type } from 'typebox';
|
||||||
|
import { isNullish, MakeStaticResponse, typeResponse } from '@shared/utils';
|
||||||
|
|
||||||
|
|
||||||
|
export const ChangeDisplayNameRes = {
|
||||||
|
'200': typeResponse('success', 'changeDisplayName.success'),
|
||||||
|
'400': typeResponse('failure', ['changeDisplayName.alreadyExist', 'changeDisplayName.invalid']),
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ChangeDisplayNameRes = MakeStaticResponse<typeof ChangeDisplayNameRes>;
|
||||||
|
|
||||||
|
export const ChangeDisplayNameReq = Type.Object({ name: Type.String({ description: 'New Display Name' }) });
|
||||||
|
type ChangeDisplayNameReq = Static<typeof ChangeDisplayNameReq>;
|
||||||
|
|
||||||
|
const USERNAME_CHECK: RegExp = /^[a-zA-Z_0-9]+$/;
|
||||||
|
const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||||
|
void _opts;
|
||||||
|
fastify.put<{ Body: ChangeDisplayNameReq }>(
|
||||||
|
'/api/user/changeDisplayName',
|
||||||
|
{ schema: { body: ChangeDisplayNameReq, response: ChangeDisplayNameRes, operationId: 'changeDisplayName' }, config: { requireAuth: true } },
|
||||||
|
async function(req, res) {
|
||||||
|
if (isNullish(req.authUser)) return;
|
||||||
|
if (isNullish(req.body.name)) {
|
||||||
|
return res.makeResponse(400, 'failure', 'changeDisplayName.invalid');
|
||||||
|
}
|
||||||
|
if (req.body.name.length < 4 || req.body.name.length > 32) {
|
||||||
|
return res.makeResponse(400, 'failure', 'changeDisplayName.invalid');
|
||||||
|
}
|
||||||
|
if (!USERNAME_CHECK.test(req.body.name)) {
|
||||||
|
return res.makeResponse(400, 'failure', 'changeDisplayName.invalid');
|
||||||
|
}
|
||||||
|
if (this.db.updateDisplayName(req.authUser.id, req.body.name)) {
|
||||||
|
return res.makeResponse(200, 'success', 'changeDisplayName.success');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return res.makeResponse(400, 'failure', 'changeDisplayName.alreadyExist');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default route;
|
||||||
|
|
@ -49,7 +49,7 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
||||||
if (isNullish(user)) {
|
if (isNullish(user)) {
|
||||||
return res.makeResponse(404, 'failure', 'userinfo.failure.unknownUser');
|
return res.makeResponse(404, 'failure', 'userinfo.failure.unknownUser');
|
||||||
}
|
}
|
||||||
|
console.log(user);
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
name: user.name,
|
name: user.name,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue