delete account
parent
c8ba965329
commit
7ede8eda45
|
@ -8,6 +8,7 @@ import {
|
||||||
isUsernameValid,
|
isUsernameValid,
|
||||||
} from "../validator/validator";
|
} from "../validator/validator";
|
||||||
import {
|
import {
|
||||||
|
ACCOUNT_STATE,
|
||||||
CALENDAR_MAX_FUTURE_BOOKING_DAYS,
|
CALENDAR_MAX_FUTURE_BOOKING_DAYS,
|
||||||
CALENDAR_MAX_SERVICE_DURATION,
|
CALENDAR_MAX_SERVICE_DURATION,
|
||||||
CALENDAR_MIN_EARLIEST_BOOKING_TIME,
|
CALENDAR_MIN_EARLIEST_BOOKING_TIME,
|
||||||
|
@ -19,12 +20,14 @@ import {
|
||||||
getUserSession,
|
getUserSession,
|
||||||
hashPassword,
|
hashPassword,
|
||||||
matchPassword,
|
matchPassword,
|
||||||
|
newFeedbackId,
|
||||||
newStoreId,
|
newStoreId,
|
||||||
newUserId,
|
newUserId,
|
||||||
saveSession,
|
saveSession,
|
||||||
} from "../utils/utils";
|
} from "../utils/utils";
|
||||||
import Store from "../models/store";
|
import Store from "../models/store";
|
||||||
import Session from "../models/session";
|
import Session from "../models/session";
|
||||||
|
import Feedback from "../models/feedback";
|
||||||
|
|
||||||
export async function SignUp(req: Request, res: Response) {
|
export async function SignUp(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
|
@ -180,6 +183,23 @@ export async function Login(req: Request, res: Response) {
|
||||||
return res.status(400).send({ err: "invalid request" });
|
return res.status(400).send({ err: "invalid request" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check user state
|
||||||
|
|
||||||
|
if (user.state === ACCOUNT_STATE.DELETED) {
|
||||||
|
// update user state back to active
|
||||||
|
|
||||||
|
User.update(
|
||||||
|
{
|
||||||
|
state: ACCOUNT_STATE.ACTIVE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
user_id: user.user_id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// create session
|
// create session
|
||||||
saveSession(req, res, user.user_id, user.username);
|
saveSession(req, res, user.user_id, user.username);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -553,3 +573,72 @@ export async function DeleteUserProfileSession(req: Request, res: Response) {
|
||||||
res.status(500).send({ err: "invalid request" });
|
res.status(500).send({ err: "invalid request" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function DeleteUserProfile(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { reason, feedback, password } = req.body;
|
||||||
|
|
||||||
|
if (!reason || !feedback || !password) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const session = await getUserSession(req);
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await User.findOne({
|
||||||
|
where: {
|
||||||
|
user_id: session.user_id,
|
||||||
|
},
|
||||||
|
attributes: ["password"],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return res.status(401).send({ err: "unauthorized" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const decodedPassword = decodeBase64(password);
|
||||||
|
|
||||||
|
const match = await matchPassword(decodedPassword, user.password);
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
return res.status(400).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// set user state to deleted
|
||||||
|
|
||||||
|
await User.update(
|
||||||
|
{
|
||||||
|
state: ACCOUNT_STATE.DELETED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
user_id: session.user_id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// delete all sessions of this user by deleting all sessions with this user_id
|
||||||
|
|
||||||
|
await Session.destroy({
|
||||||
|
where: {
|
||||||
|
user_id: session.user_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// send feedback
|
||||||
|
|
||||||
|
Feedback.create({
|
||||||
|
feedback_id: newFeedbackId(),
|
||||||
|
user_id: session.user_id,
|
||||||
|
feedback: `${reason} - ${feedback}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).send({ msg: "user deleted" });
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
res.status(500).send({ err: "invalid request" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { DataTypes, Model } from "sequelize";
|
||||||
|
import sequelize from "../database/database";
|
||||||
|
|
||||||
|
interface FeedbackAttributes {
|
||||||
|
feedback_id: string;
|
||||||
|
user_id: string;
|
||||||
|
feedback: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Feedback extends Model<FeedbackAttributes> implements FeedbackAttributes {
|
||||||
|
declare feedback_id: string;
|
||||||
|
declare user_id: string;
|
||||||
|
declare feedback: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
Feedback.init(
|
||||||
|
{
|
||||||
|
// Model attributes are defined here
|
||||||
|
feedback_id: {
|
||||||
|
primaryKey: true,
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
user_id: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
feedback: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tableName: "feedback",
|
||||||
|
sequelize, // passing the `sequelize` instance is required
|
||||||
|
createdAt: "created_at",
|
||||||
|
updatedAt: "updated_at",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Feedback;
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Feedback from "./feedback";
|
||||||
import Session from "./session";
|
import Session from "./session";
|
||||||
import Store from "./store";
|
import Store from "./store";
|
||||||
import StoreService from "./storeService";
|
import StoreService from "./storeService";
|
||||||
|
@ -14,6 +15,7 @@ function syncModels() {
|
||||||
StoreServiceActivity.sync();
|
StoreServiceActivity.sync();
|
||||||
StoreServiceActivityUsers.sync();
|
StoreServiceActivityUsers.sync();
|
||||||
Website.sync();
|
Website.sync();
|
||||||
|
Feedback.sync();
|
||||||
|
|
||||||
// UserGoogleTokens.sync(); not needed as it is created by the calendar backend
|
// UserGoogleTokens.sync(); not needed as it is created by the calendar backend
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ interface UserAttributes {
|
||||||
calendar_min_earliest_booking_time?: number;
|
calendar_min_earliest_booking_time?: number;
|
||||||
calendar_using_primary_calendar?: boolean;
|
calendar_using_primary_calendar?: boolean;
|
||||||
language: string;
|
language: string;
|
||||||
|
state?: number; // like active, deleted, etc
|
||||||
analytics_enabled: boolean;
|
analytics_enabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ class User extends Model<UserAttributes> implements UserAttributes {
|
||||||
declare calendar_min_earliest_booking_time: number;
|
declare calendar_min_earliest_booking_time: number;
|
||||||
declare calendar_using_primary_calendar: boolean;
|
declare calendar_using_primary_calendar: boolean;
|
||||||
declare language: string;
|
declare language: string;
|
||||||
|
declare state: number;
|
||||||
declare analytics_enabled: boolean;
|
declare analytics_enabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +76,10 @@ User.init(
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
|
state: {
|
||||||
|
type: DataTypes.INTEGER,
|
||||||
|
// allowNull defaults to true
|
||||||
|
},
|
||||||
analytics_enabled: {
|
analytics_enabled: {
|
||||||
type: DataTypes.BOOLEAN,
|
type: DataTypes.BOOLEAN,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
|
|
@ -34,5 +34,10 @@ router.delete(
|
||||||
sessionProtection,
|
sessionProtection,
|
||||||
userController.DeleteUserProfileSession
|
userController.DeleteUserProfileSession
|
||||||
);
|
);
|
||||||
|
router.delete(
|
||||||
|
"/profile/delete",
|
||||||
|
sessionProtection,
|
||||||
|
userController.DeleteUserProfile
|
||||||
|
);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
@ -42,6 +42,14 @@ export const USER_ANALYTICS_ENABLED_DEFAULT = true;
|
||||||
|
|
||||||
export const VALID_LANGUAGE_CODES = ["en", "de"];
|
export const VALID_LANGUAGE_CODES = ["en", "de"];
|
||||||
|
|
||||||
|
export enum ACCOUNT_STATE {
|
||||||
|
ACTIVE = 0, // everything is fine
|
||||||
|
DELETED = 1, // account still exists but is marked as deleted, can be restored or will be deleted after a certain time
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FEEDBACK_MIN_LENGTH = 3;
|
||||||
|
export const FEEDBACK_MAX_LENGTH = 1024;
|
||||||
|
|
||||||
// TODO: outdated
|
// TODO: outdated
|
||||||
export const Roles = {
|
export const Roles = {
|
||||||
// admin of the whole system independent of stores
|
// admin of the whole system independent of stores
|
||||||
|
|
|
@ -45,6 +45,10 @@ export function newSessionId() {
|
||||||
return uuidv4();
|
return uuidv4();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function newFeedbackId() {
|
||||||
|
return uuidv4();
|
||||||
|
}
|
||||||
|
|
||||||
export async function saveSession(
|
export async function saveSession(
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|
|
@ -17,6 +17,8 @@ import {
|
||||||
STORE_SERVICE_ACTIVITY_DURATION_MAX,
|
STORE_SERVICE_ACTIVITY_DURATION_MAX,
|
||||||
STORE_SERVICE_ACTIVITY_DURATION_MIN,
|
STORE_SERVICE_ACTIVITY_DURATION_MIN,
|
||||||
VALID_LANGUAGE_CODES,
|
VALID_LANGUAGE_CODES,
|
||||||
|
FEEDBACK_MAX_LENGTH,
|
||||||
|
FEEDBACK_MIN_LENGTH,
|
||||||
} from "../utils/constants";
|
} from "../utils/constants";
|
||||||
import User from "../models/user";
|
import User from "../models/user";
|
||||||
|
|
||||||
|
@ -115,3 +117,10 @@ export function isStoreServiceActivityDurationValid(
|
||||||
export function isLanguageCodeValid(languageCode: string) {
|
export function isLanguageCodeValid(languageCode: string) {
|
||||||
return VALID_LANGUAGE_CODES.includes(languageCode);
|
return VALID_LANGUAGE_CODES.includes(languageCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isFeedbackValid(feedback: string) {
|
||||||
|
return (
|
||||||
|
feedback.length >= FEEDBACK_MIN_LENGTH &&
|
||||||
|
feedback.length <= FEEDBACK_MAX_LENGTH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue