import time from django.utils.translation import gettext as _ from django.db import models from rest_framework.response import Response from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.exceptions import NotAuthenticated from pingcap_sso.api.base import Endpoint from pingcap_sso.models import ( User, UserPointStat ) from pingcap_sso.utils import time as ptime from pingcap_sso.discourse.models import DiscourseUserAuthToken from pingcap_sso.discourse.auth_core import decrypt_secure_session_cookie, hash_user_auth_token class DetailEndpoint(Endpoint): permission_classes = (AllowAny, ) def get(self, request, username, *args, **kwargs): try: user = User.objects.get(username=username) except User.DoesNotExist: return Response({ 'detail': _('user does not exist') }, status=404) point_stat = UserPointStat.get_stat(user) progress_at_current_level, min_exps, max_exps = point_stat.get_current_level_desc() return Response({ 'detail': _('success'), 'data': { 'username': user.username, 'avatar_url': user.avatar_url, 'bio': user.bio, 'joined_at': ptime.local_time_format(user.date_joined, '%Y-%m-%d'), 'level': point_stat.level, 'points': point_stat.points, 'exps': point_stat.experience, 'level_desc': { 'min_exps': min_exps, 'max_exps': max_exps, 'progress': progress_at_current_level }, 'can_edit': request.user == user } }) class MeEndpoint(Endpoint): permission_classes = (IsAuthenticated, ) def get(self, request, *args, **kwargs): user = request.user return self.success_response_with_user_data(user) def success_response_with_user_data(self, user): return Response({ 'detail': _('success'), 'data': { 'id': user.id, 'openid': user.openid, 'username': user.username, 'avatar_url': user.avatar_url, 'is_staff': user.is_staff, } }) class AskTUGMeEndpoint(MeEndpoint): permission_classes = (AllowAny, ) def get(self, request, *args, **kwargs): cookie_t = request.COOKIES.get('_t') if not (request.user and request.user.is_authenticated): if cookie_t: response = Response({ 'detail': NotAuthenticated.default_detail, }, status=401) response.delete_cookie('_t') return response else: raise NotAuthenticated() if not cookie_t: raise NotAuthenticated() cookie_t_version = None if len(cookie_t) == 32: # v0_auth_cookie, Discourse planned to remove this after v2.9 cookie_t_version = 'v0' token = cookie_t asktug_user_id = None else: cookie_t_version = 'v1' token, asktug_user_id, issued_at = decrypt_secure_session_cookie(cookie_t) if not (token and asktug_user_id and issued_at): raise NotAuthenticated() if time.time() - issued_at > 1440 * 3600: raise NotAuthenticated() try: hashed_token = hash_user_auth_token(token) asktug_user_auth_token = DiscourseUserAuthToken.objects.filter( models.Q(auth_token=hashed_token) | models.Q(prev_auth_token=hashed_token) ) if cookie_t_version == 'v1': asktug_user_auth_token = asktug_user_auth_token.get( user_id=asktug_user_id, ) else: asktug_user_auth_token = asktug_user_auth_token.get() asktug_user = asktug_user_auth_token.user except DiscourseUserAuthToken.DoesNotExist: raise NotAuthenticated() sso_user = asktug_user.get_sso_user(log_error_if_not_exists=False) if not sso_user or (sso_user.id != request.user.id): raise NotAuthenticated() return self.success_response_with_user_data(sso_user) class UserinfoEndpoint(Endpoint): permission_classes = (IsAuthenticated, ) def get(self, request, *args, **kwargs): user = request.user userinfo = { 'username': user.username, 'email': user.email, 'phone': user.phone, 'name': user.name, 'avatar_url': user.avatar_url, 'date_joined': user.date_joined, } return Response(userinfo)