API & Client: Profile update
This commit is contained in:
parent
cac4f368bf
commit
2c4f3c4462
3
Makefile
3
Makefile
@ -2,6 +2,9 @@ include Makefile.config
|
|||||||
-include Makefile.custom.config
|
-include Makefile.custom.config
|
||||||
.SILENT:
|
.SILENT:
|
||||||
|
|
||||||
|
init-db:
|
||||||
|
$(FLASK) init_db
|
||||||
|
|
||||||
make-p:
|
make-p:
|
||||||
# Launch all P targets in parallel and exit as soon as one exits.
|
# Launch all P targets in parallel and exit as soon as one exits.
|
||||||
set -m; (for p in $(P); do ($(MAKE) $$p || kill 0)& done; wait)
|
set -m; (for p in $(P); do ($(MAKE) $$p || kill 0)& done; wait)
|
||||||
|
@ -2,7 +2,7 @@ import json
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from mpwo_api.tests.base import BaseTestCase
|
from mpwo_api.tests.base import BaseTestCase
|
||||||
from mpwo_api.tests.utils import add_user
|
from mpwo_api.tests.utils import add_user, add_user_full
|
||||||
|
|
||||||
|
|
||||||
class TestAuthBlueprint(BaseTestCase):
|
class TestAuthBlueprint(BaseTestCase):
|
||||||
@ -328,14 +328,14 @@ class TestAuthBlueprint(BaseTestCase):
|
|||||||
data['message'] == 'Invalid token. Please log in again.')
|
data['message'] == 'Invalid token. Please log in again.')
|
||||||
self.assertEqual(response.status_code, 401)
|
self.assertEqual(response.status_code, 401)
|
||||||
|
|
||||||
def test_user_profile(self):
|
def test_user_profile_minimal(self):
|
||||||
add_user('test', 'test@test.com', 'test')
|
add_user('test', 'test@test.com', '12345678')
|
||||||
with self.client:
|
with self.client:
|
||||||
resp_login = self.client.post(
|
resp_login = self.client.post(
|
||||||
'/api/auth/login',
|
'/api/auth/login',
|
||||||
data=json.dumps(dict(
|
data=json.dumps(dict(
|
||||||
email='test@test.com',
|
email='test@test.com',
|
||||||
password='test'
|
password='12345678'
|
||||||
)),
|
)),
|
||||||
content_type='application/json'
|
content_type='application/json'
|
||||||
)
|
)
|
||||||
@ -356,6 +356,39 @@ class TestAuthBlueprint(BaseTestCase):
|
|||||||
self.assertFalse(data['data']['admin'])
|
self.assertFalse(data['data']['admin'])
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_user_profile_full(self):
|
||||||
|
add_user_full('test', 'test@test.com', '12345678')
|
||||||
|
with self.client:
|
||||||
|
resp_login = self.client.post(
|
||||||
|
'/api/auth/login',
|
||||||
|
data=json.dumps(dict(
|
||||||
|
email='test@test.com',
|
||||||
|
password='12345678'
|
||||||
|
)),
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = self.client.get(
|
||||||
|
'/api/auth/profile',
|
||||||
|
headers=dict(
|
||||||
|
Authorization='Bearer ' + json.loads(
|
||||||
|
resp_login.data.decode()
|
||||||
|
)['auth_token']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
self.assertTrue(data['status'] == 'success')
|
||||||
|
self.assertTrue(data['data'] is not None)
|
||||||
|
self.assertTrue(data['data']['username'] == 'test')
|
||||||
|
self.assertTrue(data['data']['email'] == 'test@test.com')
|
||||||
|
self.assertTrue(data['data']['created_at'])
|
||||||
|
self.assertFalse(data['data']['admin'])
|
||||||
|
self.assertTrue(data['data']['first_name'] == 'John')
|
||||||
|
self.assertTrue(data['data']['last_name'] == 'Doe')
|
||||||
|
self.assertTrue(data['data']['birth_date'])
|
||||||
|
self.assertTrue(data['data']['bio'] == 'just a random guy')
|
||||||
|
self.assertTrue(data['data']['location'] == 'somewhere')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_invalid_profile(self):
|
def test_invalid_profile(self):
|
||||||
with self.client:
|
with self.client:
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
@ -366,3 +399,89 @@ class TestAuthBlueprint(BaseTestCase):
|
|||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
data['message'] == 'Invalid token. Please log in again.')
|
data['message'] == 'Invalid token. Please log in again.')
|
||||||
self.assertEqual(response.status_code, 401)
|
self.assertEqual(response.status_code, 401)
|
||||||
|
|
||||||
|
def test_user_profile_valid_update(self):
|
||||||
|
add_user('test', 'test@test.com', '12345678')
|
||||||
|
with self.client:
|
||||||
|
resp_login = self.client.post(
|
||||||
|
'/api/auth/login',
|
||||||
|
data=json.dumps(dict(
|
||||||
|
email='test@test.com',
|
||||||
|
password='12345678'
|
||||||
|
)),
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = self.client.post(
|
||||||
|
'/api/auth/profile/edit',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(dict(
|
||||||
|
first_name='John',
|
||||||
|
last_name='Doe',
|
||||||
|
location='Somewhere',
|
||||||
|
bio='just a random guy',
|
||||||
|
birth_date='01/01/1980'
|
||||||
|
)),
|
||||||
|
headers=dict(
|
||||||
|
Authorization='Bearer ' + json.loads(
|
||||||
|
resp_login.data.decode()
|
||||||
|
)['auth_token']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
self.assertTrue(data['status'] == 'success')
|
||||||
|
self.assertTrue(data['message'] == 'User profile updated.')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_user_profile_valid_update_with_one_field(self):
|
||||||
|
add_user('test', 'test@test.com', '12345678')
|
||||||
|
with self.client:
|
||||||
|
resp_login = self.client.post(
|
||||||
|
'/api/auth/login',
|
||||||
|
data=json.dumps(dict(
|
||||||
|
email='test@test.com',
|
||||||
|
password='12345678'
|
||||||
|
)),
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = self.client.post(
|
||||||
|
'/api/auth/profile/edit',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(dict(
|
||||||
|
first_name='John'
|
||||||
|
)),
|
||||||
|
headers=dict(
|
||||||
|
Authorization='Bearer ' + json.loads(
|
||||||
|
resp_login.data.decode()
|
||||||
|
)['auth_token']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
self.assertTrue(data['status'] == 'success')
|
||||||
|
self.assertTrue(data['message'] == 'User profile updated.')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_user_profile_update_invalid_json(self):
|
||||||
|
add_user('test', 'test@test.com', '12345678')
|
||||||
|
with self.client:
|
||||||
|
resp_login = self.client.post(
|
||||||
|
'/api/auth/login',
|
||||||
|
data=json.dumps(dict(
|
||||||
|
email='test@test.com',
|
||||||
|
password='12345678'
|
||||||
|
)),
|
||||||
|
content_type='application/json'
|
||||||
|
)
|
||||||
|
response = self.client.post(
|
||||||
|
'/api/auth/profile/edit',
|
||||||
|
content_type='application/json',
|
||||||
|
data=json.dumps(dict()),
|
||||||
|
headers=dict(
|
||||||
|
Authorization='Bearer ' + json.loads(
|
||||||
|
resp_login.data.decode()
|
||||||
|
)['auth_token']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
data = json.loads(response.data.decode())
|
||||||
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertIn('Invalid payload.', data['message'])
|
||||||
|
self.assertIn('error', data['status'])
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import datetime
|
||||||
|
|
||||||
from mpwo_api import db
|
from mpwo_api import db
|
||||||
from mpwo_api.users.models import User
|
from mpwo_api.users.models import User
|
||||||
|
|
||||||
@ -7,3 +9,15 @@ def add_user(username, email, password):
|
|||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
def add_user_full(username, email, password):
|
||||||
|
user = User(username=username, email=email, password=password)
|
||||||
|
user.first_name = 'John'
|
||||||
|
user.last_name = 'Doe'
|
||||||
|
user.bio = 'just a random guy'
|
||||||
|
user.location = 'somewhere'
|
||||||
|
user.birth_date = datetime.datetime.strptime('01/01/1980', '%d/%m/%Y')
|
||||||
|
db.session.add(user)
|
||||||
|
db.session.commit()
|
||||||
|
return user
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import datetime
|
||||||
from flask import Blueprint, jsonify, request
|
from flask import Blueprint, jsonify, request
|
||||||
from sqlalchemy import exc, or_
|
from sqlalchemy import exc, or_
|
||||||
|
|
||||||
@ -155,6 +156,57 @@ def get_user_status(user_id):
|
|||||||
'email': user.email,
|
'email': user.email,
|
||||||
'created_at': user.created_at,
|
'created_at': user.created_at,
|
||||||
'admin': user.admin,
|
'admin': user.admin,
|
||||||
|
'first_name': user.first_name,
|
||||||
|
'last_name': user.last_name,
|
||||||
|
'bio': user.bio,
|
||||||
|
'location': user.location,
|
||||||
|
'birth_date': user.birth_date,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return jsonify(response_object), 200
|
return jsonify(response_object), 200
|
||||||
|
|
||||||
|
|
||||||
|
@auth_blueprint.route('/auth/profile/edit', methods=['POST'])
|
||||||
|
@authenticate
|
||||||
|
def edit_user(user_id):
|
||||||
|
# get post data
|
||||||
|
post_data = request.get_json()
|
||||||
|
if not post_data:
|
||||||
|
response_object = {
|
||||||
|
'status': 'error',
|
||||||
|
'message': 'Invalid payload.'
|
||||||
|
}
|
||||||
|
return jsonify(response_object), 400
|
||||||
|
first_name = post_data.get('first_name')
|
||||||
|
last_name = post_data.get('last_name')
|
||||||
|
bio = post_data.get('bio')
|
||||||
|
birth_date = post_data.get('birth_date')
|
||||||
|
location = post_data.get('location')
|
||||||
|
try:
|
||||||
|
user = User.query.filter_by(id=user_id).first()
|
||||||
|
user.first_name = first_name
|
||||||
|
user.last_name = last_name
|
||||||
|
user.bio = bio
|
||||||
|
user.location = location
|
||||||
|
user.birth_date = (
|
||||||
|
datetime.datetime.strptime(birth_date, '%d/%m/%Y')
|
||||||
|
if birth_date
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
response_object = {
|
||||||
|
'status': 'success',
|
||||||
|
'message': 'User profile updated.'
|
||||||
|
}
|
||||||
|
return jsonify(response_object), 200
|
||||||
|
|
||||||
|
# handler errors
|
||||||
|
except (exc.IntegrityError, exc.OperationalError, ValueError) as e:
|
||||||
|
db.session.rollback()
|
||||||
|
appLog.error(e)
|
||||||
|
response_object = {
|
||||||
|
'status': 'error',
|
||||||
|
'message': 'Error. Please try again or contact the administrator.'
|
||||||
|
}
|
||||||
|
return jsonify(response_object), 500
|
||||||
|
@ -9,18 +9,23 @@ from mpwo_api import bcrypt, db
|
|||||||
class User(db.Model):
|
class User(db.Model):
|
||||||
__tablename__ = "users"
|
__tablename__ = "users"
|
||||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||||
username = db.Column(db.String(80), unique=True, nullable=False)
|
username = db.Column(db.String(20), unique=True, nullable=False)
|
||||||
email = db.Column(db.String(120), unique=True, nullable=False)
|
email = db.Column(db.String(120), unique=True, nullable=False)
|
||||||
password = db.Column(db.String(255), nullable=False)
|
password = db.Column(db.String(255), nullable=False)
|
||||||
created_at = db.Column(db.DateTime, nullable=False)
|
created_at = db.Column(db.DateTime, nullable=False)
|
||||||
admin = db.Column(db.Boolean, default=False, nullable=False)
|
admin = db.Column(db.Boolean, default=False, nullable=False)
|
||||||
|
first_name = db.Column(db.String(80), nullable=True)
|
||||||
|
last_name = db.Column(db.String(80), nullable=True)
|
||||||
|
birth_date = db.Column(db.DateTime, nullable=True)
|
||||||
|
location = db.Column(db.String(80), nullable=True)
|
||||||
|
bio = db.Column(db.String(200), nullable=True)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<User %r>' % self.username
|
return '<User %r>' % self.username
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, username, email, password,
|
self, username, email, password,
|
||||||
created_at=datetime.datetime.utcnow()):
|
created_at=datetime.datetime.now()):
|
||||||
self.username = username
|
self.username = username
|
||||||
self.email = email
|
self.email = email
|
||||||
self.password = bcrypt.generate_password_hash(
|
self.password = bcrypt.generate_password_hash(
|
||||||
@ -30,7 +35,11 @@ class User(db.Model):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def encode_auth_token(user_id):
|
def encode_auth_token(user_id):
|
||||||
"""Generates the auth token"""
|
"""
|
||||||
|
Generates the auth token
|
||||||
|
:param user_id: -
|
||||||
|
:return: JWToken
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
payload = {
|
payload = {
|
||||||
'exp': datetime.datetime.utcnow() + datetime.timedelta(
|
'exp': datetime.datetime.utcnow() + datetime.timedelta(
|
||||||
|
@ -5,21 +5,18 @@ from mpwo_api.users.models import User
|
|||||||
|
|
||||||
|
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
def recreate_db():
|
def init_db():
|
||||||
"""Recreates a database."""
|
"""Init the database."""
|
||||||
db.drop_all()
|
db.drop_all()
|
||||||
db.create_all()
|
db.create_all()
|
||||||
db.session.commit()
|
admin = User(
|
||||||
print('Database (re)creation done.')
|
username='admin',
|
||||||
|
email='admin@example.com',
|
||||||
|
password='mpwoadmin')
|
||||||
@app.cli.command()
|
|
||||||
def seed_db():
|
|
||||||
"""Seeds the database."""
|
|
||||||
admin = User(username='admin', email='admin@example.com', password='admin')
|
|
||||||
admin.admin = True
|
admin.admin = True
|
||||||
db.session.add(admin)
|
db.session.add(admin)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
print('Database initialization done.')
|
||||||
|
|
||||||
|
|
||||||
@app.cli.command()
|
@app.cli.command()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import keyIndex from 'react-key-index'
|
import keyIndex from 'react-key-index'
|
||||||
|
|
||||||
import mpwoApi from '../mpwoApi'
|
import mpwoApi from '../mpwoApi'
|
||||||
|
import { history } from '../index'
|
||||||
|
|
||||||
function AuthError(message) {
|
function AuthError(message) {
|
||||||
return { type: 'AUTH_ERROR', message }
|
return { type: 'AUTH_ERROR', message }
|
||||||
@ -17,25 +19,21 @@ function ProfileError(message) {
|
|||||||
return { type: 'PROFILE_ERROR', message }
|
return { type: 'PROFILE_ERROR', message }
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateFormDataEmail = value => ({
|
export const handleFormChange = (target, value) => ({
|
||||||
type: 'UPDATE_FORMDATA_EMAIL',
|
type: 'UPDATE_USER_FORMDATA',
|
||||||
email: value,
|
target,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
|
|
||||||
const updateFormDataUsername = value => ({
|
export const updateProfileFormData = (target, value) => ({
|
||||||
type: 'UPDATE_FORMDATA_USERNAME',
|
type: 'UPDATE_PROFILE_FORMDATA',
|
||||||
username: value,
|
target,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
|
|
||||||
const updateFormDataPassword = value => ({
|
function initProfileFormData(user) {
|
||||||
type: 'UPDATE_FORMDATA_PASSWORD',
|
return { type: 'INIT_PROFILE_FORM', user }
|
||||||
password: value,
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const updateFormDataPasswordConf = value => ({
|
|
||||||
type: 'UPDATE_FORMDATA_PASSWORD_CONF',
|
|
||||||
passwordConf: value,
|
|
||||||
})
|
|
||||||
|
|
||||||
export function getProfile(dispatch) {
|
export function getProfile(dispatch) {
|
||||||
return mpwoApi
|
return mpwoApi
|
||||||
@ -43,7 +41,6 @@ export function getProfile(dispatch) {
|
|||||||
.then(ret => {
|
.then(ret => {
|
||||||
if (ret.status === 'success') {
|
if (ret.status === 'success') {
|
||||||
dispatch(ProfileSuccess(ret))
|
dispatch(ProfileSuccess(ret))
|
||||||
// window.location.href = '/'
|
|
||||||
} else {
|
} else {
|
||||||
dispatch(ProfileError(ret.message))
|
dispatch(ProfileError(ret.message))
|
||||||
}
|
}
|
||||||
@ -139,15 +136,29 @@ export function handleUserFormSubmit(event, formType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleFormChange = event => dispatch => {
|
export function initProfileForm () {
|
||||||
switch (event.target.name) {
|
return (dispatch, getState) => {
|
||||||
case 'email':
|
const state = getState()
|
||||||
return dispatch(updateFormDataEmail(event.target.value))
|
dispatch(initProfileFormData(state.user))
|
||||||
case 'username':
|
}
|
||||||
return dispatch(updateFormDataUsername(event.target.value))
|
}
|
||||||
case 'password':
|
|
||||||
return dispatch(updateFormDataPassword(event.target.value))
|
export function handleProfileFormSubmit(event) {
|
||||||
default: // case 'password-conf':
|
event.preventDefault()
|
||||||
return dispatch(updateFormDataPasswordConf(event.target.value))
|
return (dispatch, getState) => {
|
||||||
|
const state = getState()
|
||||||
|
return mpwoApi
|
||||||
|
.updateProfile(state.formProfile.formProfile)
|
||||||
|
.then(ret => {
|
||||||
|
if (ret.status === 'success') {
|
||||||
|
getProfile(dispatch)
|
||||||
|
history.push('/profile')
|
||||||
|
} else {
|
||||||
|
dispatch(AuthError(ret.message))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
throw error
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,14 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, textarea {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.page-title {
|
.page-title {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
|
@ -7,6 +7,7 @@ import Logout from './User/Logout'
|
|||||||
import NavBar from './NavBar'
|
import NavBar from './NavBar'
|
||||||
import NotFound from './NotFound'
|
import NotFound from './NotFound'
|
||||||
import Profile from './User/Profile'
|
import Profile from './User/Profile'
|
||||||
|
import ProfileEdit from './User/ProfileEdit'
|
||||||
import UserForm from './User/UserForm'
|
import UserForm from './User/UserForm'
|
||||||
import { isLoggedIn } from '../utils'
|
import { isLoggedIn } from '../utils'
|
||||||
|
|
||||||
@ -57,6 +58,18 @@ export default class App extends React.Component {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Route exact path="/logout" component={Logout} />
|
<Route exact path="/logout" component={Logout} />
|
||||||
|
<Route
|
||||||
|
exact path="/profile/edit"
|
||||||
|
render={() => (
|
||||||
|
isLoggedIn() ? (
|
||||||
|
<ProfileEdit />
|
||||||
|
) : (
|
||||||
|
<UserForm
|
||||||
|
formType={'Login'}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
exact path="/profile"
|
exact path="/profile"
|
||||||
render={() => (
|
render={() => (
|
||||||
|
@ -51,10 +51,10 @@ export default function Form (props) {
|
|||||||
{props.formType === 'Register' &&
|
{props.formType === 'Register' &&
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<input
|
<input
|
||||||
name="password-conf"
|
name="passwordConf"
|
||||||
className="form-control input-lg"
|
className="form-control input-lg"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Enter password confirmation"
|
placeholder="Enter the password confirmation"
|
||||||
required
|
required
|
||||||
onChange={props.onHandleFormChange}
|
onChange={props.onHandleFormChange}
|
||||||
/>
|
/>
|
||||||
|
@ -28,7 +28,12 @@ function Profile ({ user }) {
|
|||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-md-8">
|
<div className="col-md-8">
|
||||||
<p>Email : {user.email}</p>
|
<p>Email : {user.email}</p>
|
||||||
<p>Registration date : {user.createdAt}</p>
|
<p>Registration Date : {user.createdAt}</p>
|
||||||
|
<p>First Name : {user.firstName}</p>
|
||||||
|
<p>Last Name : {user.lastName}</p>
|
||||||
|
<p>Birth Date : {user.birthDate}</p>
|
||||||
|
<p>Location : {user.location}</p>
|
||||||
|
<p>Bio : {user.bio}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
162
mpwo_client/src/components/User/ProfileEdit.jsx
Normal file
162
mpwo_client/src/components/User/ProfileEdit.jsx
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Helmet } from 'react-helmet'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
|
||||||
|
import {
|
||||||
|
initProfileForm,
|
||||||
|
updateProfileFormData,
|
||||||
|
handleProfileFormSubmit
|
||||||
|
} from '../../actions'
|
||||||
|
|
||||||
|
|
||||||
|
class ProfileEdit extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.initForm(this.props.user)
|
||||||
|
}
|
||||||
|
render () {
|
||||||
|
const { formProfile,
|
||||||
|
onHandleFormChange,
|
||||||
|
onHandleProfileFormSubmit,
|
||||||
|
user
|
||||||
|
} = this.props
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Helmet>
|
||||||
|
<title>mpwo - {user.username} - Edit Profile</title>
|
||||||
|
</Helmet>
|
||||||
|
<div className="container">
|
||||||
|
<h1 className="page-title">Profile Edition</h1>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-2" />
|
||||||
|
<div className="col-md-8">
|
||||||
|
<div className="card">
|
||||||
|
<div className="card-header">
|
||||||
|
{user.username}
|
||||||
|
</div>
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12">
|
||||||
|
<form onSubmit={event =>
|
||||||
|
onHandleProfileFormSubmit(event)}
|
||||||
|
>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Email:
|
||||||
|
<input
|
||||||
|
name="email"
|
||||||
|
className="form-control input-lg"
|
||||||
|
type="text"
|
||||||
|
value={user.email}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>
|
||||||
|
Registration Date:
|
||||||
|
<input
|
||||||
|
name="createdAt"
|
||||||
|
className="form-control input-lg"
|
||||||
|
type="text"
|
||||||
|
value={user.createdAt}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>
|
||||||
|
First Name:
|
||||||
|
<input
|
||||||
|
name="firstName"
|
||||||
|
className="form-control input-lg"
|
||||||
|
type="text"
|
||||||
|
value={formProfile.firstName}
|
||||||
|
onChange={onHandleFormChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>
|
||||||
|
Last Name:
|
||||||
|
<input
|
||||||
|
name="lastName"
|
||||||
|
className="form-control input-lg"
|
||||||
|
type="text"
|
||||||
|
value={formProfile.lastName}
|
||||||
|
onChange={onHandleFormChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>
|
||||||
|
Birth Date
|
||||||
|
<input
|
||||||
|
name="birthDate"
|
||||||
|
className="form-control input-lg"
|
||||||
|
type="text"
|
||||||
|
value={formProfile.birthDate}
|
||||||
|
onChange={onHandleFormChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>
|
||||||
|
Location:
|
||||||
|
<input
|
||||||
|
name="location"
|
||||||
|
className="form-control input-lg"
|
||||||
|
type="text"
|
||||||
|
value={formProfile.location}
|
||||||
|
onChange={onHandleFormChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>
|
||||||
|
Bio:
|
||||||
|
<textarea
|
||||||
|
name="bio"
|
||||||
|
className="form-control input-lg"
|
||||||
|
maxLength="200"
|
||||||
|
type="text"
|
||||||
|
value={formProfile.bio}
|
||||||
|
onChange={onHandleFormChange}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
className="btn btn-primary btn-lg btn-block"
|
||||||
|
value="Submit"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
state => ({
|
||||||
|
formProfile: state.formProfile.formProfile,
|
||||||
|
user: state.user,
|
||||||
|
}),
|
||||||
|
dispatch => ({
|
||||||
|
initForm: () => {
|
||||||
|
dispatch(initProfileForm())
|
||||||
|
},
|
||||||
|
onHandleFormChange: event => {
|
||||||
|
dispatch(updateProfileFormData(event.target.name, event.target.value))
|
||||||
|
},
|
||||||
|
onHandleProfileFormSubmit: event => {
|
||||||
|
dispatch(handleProfileFormSubmit(event))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)(ProfileEdit)
|
@ -47,7 +47,7 @@ export default connect(
|
|||||||
}),
|
}),
|
||||||
dispatch => ({
|
dispatch => ({
|
||||||
onHandleFormChange: event => {
|
onHandleFormChange: event => {
|
||||||
dispatch(handleFormChange(event))
|
dispatch(handleFormChange(event.target.name, event.target.value))
|
||||||
},
|
},
|
||||||
onHandleUserFormSubmit: (event, formType) => {
|
onHandleUserFormSubmit: (event, formType) => {
|
||||||
dispatch(handleUserFormSubmit(event, formType))
|
dispatch(handleUserFormSubmit(event, formType))
|
||||||
|
@ -46,4 +46,23 @@ export default class MpwoApi {
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.catch(error => error)
|
.catch(error => error)
|
||||||
}
|
}
|
||||||
|
static updateProfile(form) {
|
||||||
|
const request = new Request(`${apiUrl}auth/profile/edit`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: new Headers({
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${window.localStorage.getItem('authToken')}`,
|
||||||
|
}),
|
||||||
|
body: JSON.stringify({
|
||||||
|
first_name: form.firstName,
|
||||||
|
last_name: form.lastName,
|
||||||
|
bio: form.bio,
|
||||||
|
location: form.location,
|
||||||
|
birth_date: form.birthdate,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
return fetch(request)
|
||||||
|
.then(response => response.json())
|
||||||
|
.catch(error => error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,32 +4,11 @@ import initial from './initial'
|
|||||||
|
|
||||||
const formData = (state = initial.formData, action) => {
|
const formData = (state = initial.formData, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'UPDATE_FORMDATA_EMAIL':
|
case 'UPDATE_USER_FORMDATA':
|
||||||
return {
|
return {
|
||||||
formData: {
|
formData: {
|
||||||
...state.formData,
|
...state.formData,
|
||||||
email: action.email
|
[action.target]: action.value
|
||||||
},
|
|
||||||
}
|
|
||||||
case 'UPDATE_FORMDATA_USERNAME':
|
|
||||||
return {
|
|
||||||
formData: {
|
|
||||||
...state.formData,
|
|
||||||
username: action.username
|
|
||||||
},
|
|
||||||
}
|
|
||||||
case 'UPDATE_FORMDATA_PASSWORD':
|
|
||||||
return {
|
|
||||||
formData: {
|
|
||||||
...state.formData,
|
|
||||||
password: action.password
|
|
||||||
},
|
|
||||||
}
|
|
||||||
case 'UPDATE_FORMDATA_PASSWORD_CONF':
|
|
||||||
return {
|
|
||||||
formData: {
|
|
||||||
...state.formData,
|
|
||||||
passwordConf: action.passwordConf
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case 'PROFILE_SUCCESS':
|
case 'PROFILE_SUCCESS':
|
||||||
@ -39,6 +18,33 @@ const formData = (state = initial.formData, action) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formProfile = (state = initial.formProfile, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'UPDATE_PROFILE_FORMDATA':
|
||||||
|
return {
|
||||||
|
formProfile: {
|
||||||
|
...state.formProfile,
|
||||||
|
[action.target]: action.value
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case 'INIT_PROFILE_FORM':
|
||||||
|
return {
|
||||||
|
formProfile: {
|
||||||
|
...state.formProfile,
|
||||||
|
firstName: action.user.firstName,
|
||||||
|
lastName: action.user.lastName,
|
||||||
|
birthDate: action.user.birthDate,
|
||||||
|
location: action.user.location,
|
||||||
|
bio: action.user.bio,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case 'PROFILE_SUCCESS':
|
||||||
|
return initial.formProfile
|
||||||
|
default:
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const message = (state = initial.message, action) => {
|
const message = (state = initial.message, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'AUTH_ERROR':
|
case 'AUTH_ERROR':
|
||||||
@ -73,14 +79,29 @@ const user = (state = initial.user, action) => {
|
|||||||
case 'LOGOUT':
|
case 'LOGOUT':
|
||||||
window.localStorage.removeItem('authToken')
|
window.localStorage.removeItem('authToken')
|
||||||
return initial.user
|
return initial.user
|
||||||
case 'PROFILE_SUCCESS':
|
case 'PROFILE_SUCCESS':
|
||||||
return {
|
return {
|
||||||
id: action.message.data.id,
|
id: action.message.data.id,
|
||||||
username: action.message.data.username,
|
username: action.message.data.username,
|
||||||
email: action.message.data.email,
|
email: action.message.data.email,
|
||||||
isAdmin: action.message.data.admin,
|
isAdmin: action.message.data.admin,
|
||||||
createdAt: action.message.data.created_at,
|
createdAt: action.message.data.created_at,
|
||||||
isAuthenticated: true
|
isAuthenticated: true,
|
||||||
|
firstName: action.message.data.first_name
|
||||||
|
? action.message.data.first_name
|
||||||
|
: '',
|
||||||
|
lastName: action.message.data.last_name
|
||||||
|
? action.message.data.last_name
|
||||||
|
: '',
|
||||||
|
bio: action.message.data.bio
|
||||||
|
? action.message.data.bio
|
||||||
|
: '',
|
||||||
|
location: action.message.data.location
|
||||||
|
? action.message.data.location
|
||||||
|
: '',
|
||||||
|
birthDate: action.message.data.birth_date
|
||||||
|
? action.message.data.birth_date
|
||||||
|
: '',
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return state
|
return state
|
||||||
@ -89,6 +110,7 @@ const user = (state = initial.user, action) => {
|
|||||||
|
|
||||||
const reducers = combineReducers({
|
const reducers = combineReducers({
|
||||||
formData,
|
formData,
|
||||||
|
formProfile,
|
||||||
message,
|
message,
|
||||||
messages,
|
messages,
|
||||||
user,
|
user,
|
||||||
|
@ -8,13 +8,27 @@ export default {
|
|||||||
createdAt: '',
|
createdAt: '',
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
bio: '',
|
||||||
|
location: '',
|
||||||
|
birthDate: ''
|
||||||
},
|
},
|
||||||
formData: {
|
formData: {
|
||||||
formData: {
|
formData: {
|
||||||
username: '',
|
username: '',
|
||||||
email: '',
|
email: '',
|
||||||
password: '',
|
password: '',
|
||||||
passwordConf: '',
|
passwordConf: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
formProfile: {
|
||||||
|
formProfile: {
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
bio: '',
|
||||||
|
location: '',
|
||||||
|
birthDate: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user