1616 You should have received a copy of the GNU General Public License
1717 along with this program. If not, see <https://www.gnu.org/licenses/>.
1818"""
19+ import datetime
20+ import os
21+
1922import flask_jwt_extended as fjwt
23+ import Geohash
2024import PyMatcha .models .user as user
2125from flask import Blueprint
2226from flask import request
27+ from ip2geotools .databases .noncommercial import DbIpCity
2328from PyMatcha .errors import BadRequestError
29+ from PyMatcha .errors import NotFoundError
30+ from PyMatcha .errors import UnauthorizedError
31+ from PyMatcha .models .tag import Tag
2432from PyMatcha .success import Success
33+ from PyMatcha .utils import hash_password
34+ from PyMatcha .utils .confirm_token import generate_confirmation_token
2535from PyMatcha .utils .decorators import validate_params
36+ from PyMatcha .utils .mail import send_mail_text
2637
2738User = user .User
2839get_user = user .get_user
2940
3041profile_bp = Blueprint ("profile" , __name__ )
3142
32- REQUIRED_PARAMS_COMPLETE_PROFILE = {
33- "orientation" : str ,
43+ REQUIRED_PARAMS_COMPLETE_PROFILE = {"gender" : str , "birthdate" : int , "orientation" : str , "bio" : str , "tags" : list }
44+ REQUIRED_PARAMS_EDIT_PROFILE = {
45+ "first_name" : str ,
46+ "last_name" : str ,
47+ "username" : str ,
3448 "bio" : str ,
35- # "tags": str
49+ "gender" : str ,
50+ "orientation" : str ,
51+ "birthdate" : int ,
52+ "tags" : list ,
3653}
3754
3855
@@ -48,12 +65,127 @@ def complete_profile():
4865 data = request .get_json ()
4966 orientation = data ["orientation" ]
5067 bio = data ["bio" ]
68+ tags = data ["tags" ]
69+ gender = data ["gender" ]
70+ birthdate = data ["birthdate" ]
5171
52- if orientation not in [ "heterosexual" , "homosexual" , "bisexual" , "other" ] :
53- raise BadRequestError ( "Genre must be heterosexual, homosexual, bisexual or other" , "Try again" )
72+ for tag in tags :
73+ Tag . create ( name = tag , user_id = current_user . id )
5474
5575 current_user .orientation = orientation
5676 current_user .bio = bio
5777 current_user .is_profile_completed = True
78+ current_user .gender = gender
79+ current_user .birthdate = datetime .date .fromtimestamp (int (birthdate ))
5880 current_user .save ()
5981 return Success ("Profile completed !" )
82+
83+
84+ @profile_bp .route ("/profile/edit" , methods = ["PUT" ])
85+ @fjwt .jwt_required
86+ @validate_params (REQUIRED_PARAMS_EDIT_PROFILE )
87+ def edit_profile ():
88+ current_user = fjwt .current_user
89+ if not current_user .is_profile_completed :
90+ raise BadRequestError ("The user has not completed his profile" , "Complete your profile and try again" )
91+ data = request .get_json ()
92+ first_name = data ["first_name" ]
93+ last_name = data ["last_name" ]
94+ username = data ["username" ]
95+ bio = data ["bio" ]
96+ gender = data ["gender" ]
97+ orientation = data ["orientation" ]
98+ birthdate = data ["birthdate" ]
99+
100+ try :
101+ get_user (username )
102+ except NotFoundError :
103+ pass
104+ else :
105+ raise BadRequestError ("Username taken" , "Try again" )
106+
107+ if orientation not in ["heterosexual" , "homosexual" , "bisexual" , "other" ]:
108+ raise BadRequestError ("Orientation must be heterosexual, homosexual, bisexual or other" , "Try again" )
109+
110+ if gender not in ["male" , "female" , "other" ]:
111+ raise BadRequestError ("Gender must be male, female or other" , "Try again" )
112+
113+ birthdate = datetime .date .fromtimestamp (birthdate )
114+
115+ current_user .first_name = first_name
116+ current_user .last_name = last_name
117+ current_user .username = username
118+ current_user .bio = bio
119+ current_user .gender = gender
120+ current_user .orientation = orientation
121+ current_user .birthdate = birthdate
122+ current_user .save ()
123+ return Success ("User successfully modified !" )
124+
125+
126+ @profile_bp .route ("/profile/edit/email" , methods = ["PUT" ])
127+ @fjwt .jwt_required
128+ @validate_params ({"email" : str })
129+ def edit_email ():
130+ data = request .get_json ()
131+ new_email = data ["email" ].lower ()
132+ current_user = fjwt .current_user
133+ if current_user .email == new_email :
134+ raise BadRequestError ("The new email is the same as the old one !" , "Try again" )
135+ current_user .email = new_email
136+ current_user .is_confirmed = False
137+ current_user .save ()
138+ token = generate_confirmation_token (email = new_email , token_type = "confirm" )
139+ send_mail_text .delay (
140+ dest = data ["email" ],
141+ subject = "Confirm your new email for PyMatcha" ,
142+ body = os .getenv ("APP_URL" ) + "/auth/confirm/" + token ,
143+ )
144+ return Success ("Email sent for new email" )
145+
146+
147+ @profile_bp .route ("/profile/edit/password" , methods = ["PUT" ])
148+ @fjwt .jwt_required
149+ @validate_params ({"old_password" : str , "new_password" : str })
150+ def edit_password ():
151+ data = request .get_json ()
152+ old_password = data ["old_password" ]
153+ new_password = data ["new_password" ]
154+ current_user = fjwt .current_user
155+ if not current_user .check_password (old_password ):
156+ raise UnauthorizedError ("Incorrect password" , "Try again" )
157+ current_user .password = hash_password (new_password )
158+ current_user .save ()
159+ # TODO: Send mail
160+ send_mail_text .delay (
161+ dest = current_user .email ,
162+ subject = "Password change notification" ,
163+ body = f"Your password was changed at { datetime .datetime .utcnow ()} ."
164+ f" If you believe it wasn't you, please change it immediatly" ,
165+ )
166+ return Success ("User password successfully updated." )
167+
168+
169+ @profile_bp .route ("/profile/edit/geolocation" , methods = ["PUT" ])
170+ @fjwt .jwt_required
171+ @validate_params ({"ip" : str }, {"lat" : float , "lng" : float })
172+ def edit_geolocation ():
173+ data = request .get_json ()
174+ ip = data ["ip" ]
175+ current_user = fjwt .current_user
176+ try :
177+ lat = data ["lat" ]
178+ lng = data ["lng" ]
179+ except KeyError :
180+ lat = None
181+ lng = None
182+
183+ if lat and lng :
184+ current_user .geohash = Geohash .encode (lat , lng )
185+ else :
186+ response = DbIpCity .get (ip , api_key = "free" )
187+ lat = response .latitude
188+ lng = response .longitude
189+ current_user .geohash = Geohash .encode (lat , lng )
190+ current_user .save ()
191+ return Success ("New location sucessfully saved." )
0 commit comments