delete account
parent
c8ba965329
commit
7ede8eda45
|
@ -8,6 +8,7 @@ import {
|
|||
isUsernameValid,
|
||||
} from "../validator/validator";
|
||||
import {
|
||||
ACCOUNT_STATE,
|
||||
CALENDAR_MAX_FUTURE_BOOKING_DAYS,
|
||||
CALENDAR_MAX_SERVICE_DURATION,
|
||||
CALENDAR_MIN_EARLIEST_BOOKING_TIME,
|
||||
|
@ -19,12 +20,14 @@ import {
|
|||
getUserSession,
|
||||
hashPassword,
|
||||
matchPassword,
|
||||
newFeedbackId,
|
||||
newStoreId,
|
||||
newUserId,
|
||||
saveSession,
|
||||
} from "../utils/utils";
|
||||
import Store from "../models/store";
|
||||
import Session from "../models/session";
|
||||
import Feedback from "../models/feedback";
|
||||
|
||||
export async function SignUp(req: Request, res: Response) {
|
||||
try {
|
||||
|
@ -180,6 +183,23 @@ export async function Login(req: Request, res: Response) {
|
|||
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
|
||||
saveSession(req, res, user.user_id, user.username);
|
||||
} catch (error) {
|
||||
|
@ -553,3 +573,72 @@ export async function DeleteUserProfileSession(req: Request, res: Response) {
|
|||
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 Store from "./store";
|
||||
import StoreService from "./storeService";
|
||||
|
@ -14,6 +15,7 @@ function syncModels() {
|
|||
StoreServiceActivity.sync();
|
||||
StoreServiceActivityUsers.sync();
|
||||
Website.sync();
|
||||
Feedback.sync();
|
||||
|
||||
// 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_using_primary_calendar?: boolean;
|
||||
language: string;
|
||||
state?: number; // like active, deleted, etc
|
||||
analytics_enabled: boolean;
|
||||
}
|
||||
|
||||
|
@ -27,6 +28,7 @@ class User extends Model<UserAttributes> implements UserAttributes {
|
|||
declare calendar_min_earliest_booking_time: number;
|
||||
declare calendar_using_primary_calendar: boolean;
|
||||
declare language: string;
|
||||
declare state: number;
|
||||
declare analytics_enabled: boolean;
|
||||
}
|
||||
|
||||
|
@ -74,6 +76,10 @@ User.init(
|
|||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
},
|
||||
state: {
|
||||
type: DataTypes.INTEGER,
|
||||
// allowNull defaults to true
|
||||
},
|
||||
analytics_enabled: {
|
||||
type: DataTypes.BOOLEAN,
|
||||
allowNull: false,
|
||||
|
|
|
@ -34,5 +34,10 @@ router.delete(
|
|||
sessionProtection,
|
||||
userController.DeleteUserProfileSession
|
||||
);
|
||||
router.delete(
|
||||
"/profile/delete",
|
||||
sessionProtection,
|
||||
userController.DeleteUserProfile
|
||||
);
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -42,6 +42,14 @@ export const USER_ANALYTICS_ENABLED_DEFAULT = true;
|
|||
|
||||
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
|
||||
export const Roles = {
|
||||
// admin of the whole system independent of stores
|
||||
|
|
|
@ -45,6 +45,10 @@ export function newSessionId() {
|
|||
return uuidv4();
|
||||
}
|
||||
|
||||
export function newFeedbackId() {
|
||||
return uuidv4();
|
||||
}
|
||||
|
||||
export async function saveSession(
|
||||
req: Request,
|
||||
res: Response,
|
||||
|
|
|
@ -17,6 +17,8 @@ import {
|
|||
STORE_SERVICE_ACTIVITY_DURATION_MAX,
|
||||
STORE_SERVICE_ACTIVITY_DURATION_MIN,
|
||||
VALID_LANGUAGE_CODES,
|
||||
FEEDBACK_MAX_LENGTH,
|
||||
FEEDBACK_MIN_LENGTH,
|
||||
} from "../utils/constants";
|
||||
import User from "../models/user";
|
||||
|
||||
|
@ -115,3 +117,10 @@ export function isStoreServiceActivityDurationValid(
|
|||
export function isLanguageCodeValid(languageCode: string) {
|
||||
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