Skip to content

Commit e0fcd3c

Browse files
committed
completed settings
1 parent 763d669 commit e0fcd3c

File tree

16 files changed

+226
-17
lines changed

16 files changed

+226
-17
lines changed

velog-backend/src/database/models/User.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import { generate } from 'lib/token';
55
import UserProfile, { type UserProfileModel } from './UserProfile';
66

77
export interface UserModel {
8-
id: string,
9-
username: string,
10-
email: string,
8+
id: string;
9+
username: string;
10+
email: string;
1111
// static findUser(type: 'email' | 'username', value: string): Promise<*>,
12-
generateToken(): string,
13-
validatePassword(password: string): Promise<boolean>,
14-
getProfile(): Promise<UserProfileModel>
12+
generateToken(): string;
13+
validatePassword(password: string): Promise<boolean>;
14+
getProfile(): Promise<UserProfileModel>;
1515
}
1616

1717
const User = db.define('user', {
@@ -46,10 +46,10 @@ User.prototype.getProfile = async function getProfile(): Promise<*> {
4646
User.prototype.generateToken = async function generateToken(): Promise<string> {
4747
type TokenPayload = {
4848
id: string,
49-
username: string
49+
username: string,
5050
};
5151

52-
const { id, username } : TokenPayload = this;
52+
const { id, username }: TokenPayload = this;
5353
const userProfile: UserProfileModel = await UserProfile.findByUserId(id);
5454
if (!userProfile) {
5555
throw new Error('user profile not found');

velog-backend/src/router/me/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ const me: Router = new Router();
88
me.use('/categories', categories.routes());
99
me.use('/follow', follow.routes());
1010
me.patch('/profile', meCtrl.updateProfile);
11+
me.get('/unregister-token', meCtrl.generateUnregisterToken);
12+
me.post('/unregister', meCtrl.unregister);
1113

1214
export default me;

velog-backend/src/router/me/me.ctrl.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
import type { Context } from 'koa';
33
import UserProfile from 'database/models/UserProfile';
44
import { validateSchema } from 'lib/common';
5+
import { generate, decode } from 'lib/token';
6+
57
import Joi from 'joi';
8+
import User from '../../database/models/User';
69

710
export const updateProfile = async (ctx: Context): Promise<*> => {
811
const { user } = ctx;
@@ -56,3 +59,46 @@ export const updateProfile = async (ctx: Context): Promise<*> => {
5659
ctx.throw(500, e);
5760
}
5861
};
62+
63+
export const generateUnregisterToken = async (ctx: Context) => {
64+
const { username } = ctx.user;
65+
try {
66+
const token = await generate(
67+
{ username },
68+
{
69+
expiresIn: '1h',
70+
subject: 'unregister',
71+
},
72+
);
73+
ctx.body = {
74+
unregister_token: token,
75+
};
76+
} catch (e) {
77+
ctx.throw(500, e);
78+
}
79+
};
80+
81+
export const unregister = async (ctx: Context) => {
82+
const { username, id } = ctx.user;
83+
const schema = Joi.object().keys({
84+
unregister_token: Joi.string().required(),
85+
});
86+
87+
if (!validateSchema(ctx, schema)) return;
88+
89+
const unregisterToken = (ctx.request.body: any).unregister_token;
90+
try {
91+
const decoded = await decode(unregisterToken);
92+
if (decoded.username !== username) {
93+
ctx.status = 400;
94+
return;
95+
}
96+
const user = await User.findById(id);
97+
await user.destroy();
98+
ctx.cookies.set('access_token', 'asdf');
99+
// 탈퇴처리
100+
ctx.status = 204;
101+
} catch (e) {
102+
ctx.status = 400;
103+
}
104+
};

velog-backend/src/router/users/users.ctrl.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import db from 'database/db';
44
import { User, PostsTags, UserProfile } from 'database/models';
55
import { pick } from 'lodash';
66

7-
export const getUser = async (ctx: Context, next: () => Promise<*>): Promise<*> => {
7+
export const getUser = async (
8+
ctx: Context,
9+
next: () => Promise<*>,
10+
): Promise<*> => {
811
const { username } = ctx.params;
912
try {
1013
const user = await User.findOne({
@@ -29,14 +32,13 @@ export const getProfile = async (ctx: Context) => {
2932
const profile = await ctx.selectedUser.getProfile();
3033
ctx.body = {
3134
user_id: ctx.selectedUser.id,
32-
...pick(profile, ['display_name', 'short_bio', 'thumbnail'])
35+
...pick(profile, ['display_name', 'short_bio', 'thumbnail']),
3336
};
3437
} catch (e) {
3538
ctx.throw(500, e);
3639
}
3740
};
3841

39-
4042
export const getTags = async (ctx: Context) => {
4143
const { id } = ctx.selectedUser;
4244
try {

velog-frontend/src/components/base/UserMenu/UserMenu.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const UserMenu = ({ onClick, onLogout, username }: Props) => {
2323
<UserMenuItem to="/write">새 글 작성</UserMenuItem>
2424
<UserMenuItem to="/saves">임시 글</UserMenuItem>
2525
<div className="separator" />
26-
<UserMenuItem>설정</UserMenuItem>
26+
<UserMenuItem to="/settings">설정</UserMenuItem>
2727
<UserMenuItem onClick={onLogout}>로그아웃</UserMenuItem>
2828
</div>
2929
</div>

velog-frontend/src/components/common/Button/Button.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type Props = {
1414
children: Node,
1515
large?: boolean,
1616
fullWidth?: boolean,
17+
color?: string,
1718
};
1819

1920
const Button = ({
@@ -26,9 +27,10 @@ const Button = ({
2627
to,
2728
large,
2829
fullWidth,
30+
color,
2931
...rest
3032
}: Props) => {
31-
const processedClassName = cx('Button', theme, className, {
33+
const processedClassName = cx('Button', theme, className, color, {
3234
confirm,
3335
cancel,
3436
violetFont,
@@ -58,6 +60,7 @@ Button.defaultProps = {
5860
to: null,
5961
large: false,
6062
fullWidth: false,
63+
color: '',
6164
};
6265

6366
export default Button;

velog-frontend/src/components/common/Button/Button.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@
5252
color: $oc-violet-5;
5353
cursor: pointer;
5454
}
55+
&.red {
56+
border: 1px solid $oc-red-8;
57+
color: $oc-red-8;
58+
font-weight: 500;
59+
&:hover {
60+
color: white;
61+
background: $oc-red-6;
62+
border: 1px solid $oc-red-6;
63+
}
64+
&:active {
65+
background: $oc-red-7;
66+
border: 1px solid $oc-red-7;
67+
}
68+
}
5569
}
5670
&.paper {
5771
@include common-button-style();

velog-frontend/src/components/common/QuestionModal/QuestionModal.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ type Props = {
1616
const QuestionModal = ({ title, description, confirmText, onConfirm, onCancel, open }: Props) => (
1717
<ModalWrapper open={open}>
1818
<div className="QuestionModal">
19-
<div className="purple-line" />
2019
<div className="modal-content">
2120
{title && <h4>{title}</h4>}
2221
<p>{description}</p>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @flow
2+
import React from 'react';
3+
import Button from 'components/common/Button';
4+
import './SettingsEtc.scss';
5+
6+
type Props = {
7+
onAskUnregister: () => void,
8+
};
9+
10+
const SettingsEtc = ({ onAskUnregister }: Props) => (
11+
<div className="SettingsEtc">
12+
<section>
13+
<Button theme="outline" color="red" onClick={onAskUnregister}>
14+
회원 탈퇴
15+
</Button>
16+
</section>
17+
</div>
18+
);
19+
20+
export default SettingsEtc;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import 'utils';
2+
3+
.SettingsEtc {
4+
5+
}

0 commit comments

Comments
 (0)