From 884dffa608bb1d78fc3dc24505246a065b91ea19 Mon Sep 17 00:00:00 2001 From: whatislove118 Date: Tue, 10 Aug 2021 15:55:43 +0300 Subject: [PATCH 1/6] add requirements --- requirements.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f55397a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +asgiref==3.4.1 +Django==3.2.6 +djangorestframework==3.12.4 +Pillow==8.3.1 +pytz==2021.1 +sqlparse==0.4.1 From 4985c5a6e6068e1bfa4224602f847076f985ecf2 Mon Sep 17 00:00:00 2001 From: whatislove118 Date: Thu, 12 Aug 2021 15:28:31 +0300 Subject: [PATCH 2/6] add_jwt_auth --- questions/migrations/0001_initial.py | 2 +- .../__pycache__/0001_initial.cpython-38.pyc | Bin 1349 -> 0 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 182 -> 0 bytes requirements.txt | 5 + .../__pycache__/settings.cpython-38.pyc | Bin 2601 -> 3327 bytes .../__pycache__/urls.cpython-38.pyc | Bin 1105 -> 1101 bytes stackoverflow_api/jwt_authorization.py | 87 ++++++++++++++ stackoverflow_api/settings.py | 87 +++++++++++--- stackoverflow_api/urls.py | 2 +- users/__pycache__/models.cpython-38.pyc | Bin 496 -> 3755 bytes users/migrations/0001_initial.py | 2 +- users/migrations/0002_auto_20210811_1219.py | 71 +++++++++++ .../__pycache__/0001_initial.cpython-38.pyc | Bin 2391 -> 0 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 178 -> 0 bytes users/models.py | 112 +++++++++++++++++- users/serializers.py | 34 ++++++ users/urls.py | 11 ++ users/views.py | 28 ++++- 18 files changed, 417 insertions(+), 24 deletions(-) delete mode 100644 questions/migrations/__pycache__/0001_initial.cpython-38.pyc delete mode 100644 questions/migrations/__pycache__/__init__.cpython-38.pyc create mode 100644 stackoverflow_api/jwt_authorization.py create mode 100644 users/migrations/0002_auto_20210811_1219.py delete mode 100644 users/migrations/__pycache__/0001_initial.cpython-38.pyc delete mode 100644 users/migrations/__pycache__/__init__.cpython-38.pyc create mode 100644 users/serializers.py create mode 100644 users/urls.py diff --git a/questions/migrations/0001_initial.py b/questions/migrations/0001_initial.py index 825efb2..27bba48 100644 --- a/questions/migrations/0001_initial.py +++ b/questions/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.5 on 2021-08-10 12:45 +# Generated by Django 3.2.6 on 2021-08-10 13:01 from django.conf import settings from django.db import migrations, models diff --git a/questions/migrations/__pycache__/0001_initial.cpython-38.pyc b/questions/migrations/__pycache__/0001_initial.cpython-38.pyc deleted file mode 100644 index c19465ac2b0f1f036b7232f6538d937750cd7792..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1349 zcmZux&2rl|5GF`Uq$o;u9OuWKP7b~4BH6h#)5&DwN_OIDZMU_2;RQnpD;gB|6N0j% zT-&SPAvyLD`YO2gK7W*x}UGTiq@eCY)lw09%O~d$ID|d&D z%1fN`8(f&dh%gco5Ta#Mn28lwi5=LLZiznZQmL9r#z4rEsrI`&Hc@$rQ+`DZ1B`$$BQO~WEU@1?nxN)^_rCMNK&g%PE_(Wvy@T2Y>#~hX z+eB?s$ANqCR_w+1<86(_?&*k8lWkp_72^H>MZCq>uA)9zMSY0c1I(<(_#FQc?mhe* zkv*>Q*nhKmbSE1}XA_yhW441#f1z5(Yg)(3{c!e;YD`3!&Xt`mgix(4rPvWr zf-=htyTz{ZXwEnYCY3YHk_1vbEchG>9a6Qpq!?7=)#Tw2|W zQsq&Ky|)m6vQO!oMJO~9Y7S3%iEI>>j=n9g!aNTr=*S?4ltDUO7N*|X*gqe?rsrn| zKhfjU(ZTo1|K!0zs`jv=`dD{(pW(Dvl{SIr^WO0~AnKIc#xfNx)-p+9UY`8xiBrzwmxTx!)D zozj!j@#~|LSIWzBSUtyIjpA#}vsymV!8z7P4z4cntxAzy!rtDq!3gBM%<{nxMHa)f zlr&!sWEoE9xL?eKu6WJ|Ys%%|_N@wsgstg`kg4ZQNi6Hthh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10cKeRZts93)| zBe5j2I48d>)zHvF-zBv;yClCrKcFZ-D>b>KIKH4#zqlkZIU6Wnl$MiU9-ml{sb5%{ uT3nKupI5A(o0(n&)DL3D$7kkcmc+;F6;$5hu*uC&Da}c>16leRh#3Id>oBVT diff --git a/requirements.txt b/requirements.txt index f55397a..c365563 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,11 @@ asgiref==3.4.1 Django==3.2.6 +django-ckeditor==6.1.0 +django-js-asset==1.2.2 djangorestframework==3.12.4 +djangorestframework-simplejwt==4.7.2 Pillow==8.3.1 +PyJWT==2.1.0 pytz==2021.1 sqlparse==0.4.1 +typing==3.7.4.3 diff --git a/stackoverflow_api/__pycache__/settings.cpython-38.pyc b/stackoverflow_api/__pycache__/settings.cpython-38.pyc index cf15b77a342d37d3908ed79f097e794745a0928b..786c1044676205b7faaa93be3260bc887594cf59 100644 GIT binary patch delta 1451 zcmZ`&y>l8z6lafvy8|JiFN`ExvaNh!%OY|j=R5HU7ID%63U|cOrr2C~D};rV z60HTu2uLIbGAIy%D2zZ1Mqv!%Fb)&7C>e!Gn1X3Yz!gZsOidzVFiYYv#}v3a7pNf! z!!?+P1-K43YGNJ1%_m|Fk#XoPk_mVN-sHr$<^u5c6QPdCB)@P9-XYVFA_-o=6@HTZ z%&@5a2izjFaGT6Aw0HICHLhDa5_qclbA0DWAPdcTSSHu`gA`ak^y9w9!|6jFhj+;h z7K9ZY?mkA`cn{uxj9``58HRf-0>bJ306v6|;A8j%K84TVbNGUD?}K_lv-TuGZh~M0 zQkml<%A$zk*7q5(hHLe=g&%K`QJXm~-Lb8G)@j)fN%AtLPJREN!S*`t@eAQ7_)Ry& zns?exH-_7G>wu*TEvMS*bmg?;T5i3X?n-H%zHX&Sc<3P^A9v&F?=3ss>2%JSW9Ocs zqW_Du&^z&d9w{`C99C^L!8t)gEQ0mO$&parxVw5Ug-CdfSvIrDMBX&Fs9G`erLsm; zQ!5n*LLG?Ic9>1;(9OT@JTn4sdwR;Vh`pU~eYPTCKg}S$2o6K!J zWKCyTtyY=im>w8Jd>?fm9WWBybL%8(vmKsbm$DxYPD1{>h_qjCwq53=5@cGz zs9D;?MXGB#Y-$Be5@nn#VURTI-oVS^;sbTzZ7YlcbHoQccSr}4g!@yb@# z6X+_B>7{k8NEB6H=Z!P-1rjy1^y(hVOgL}zyywsS zUwKAIEe<3~p;e`HAheu;43^8hKa(x+Q4XX7%iV3%zq5nKe@YP)Rth+)sr`TCMK$7^ zd=4dZ5HbWArMn9l?D3QujX^jDRJ@-sKZsEkJX z&y;xy2}t-`jQ4+2R=*q*OT18%n!4#ZIVb1j{?9Mx+-c?_U23UnMBw(;PwHP)LHIFi z{p2{PCO5cgif#%qzVWPAwa{XKqCm!C=`ScMg&pBpdyY1GfZPh zU=c~Akj4_0O@*php>eDl3Nkst6cIocIpnd1b(1g=8)w86=>l%i1a9LF*WJwtxOdi& zm`E2qN zVrBeEtck<#(ueUEc_a_q*~R?>badNv%5BH?U3OINd4}tiPjt_F?YPih>0JihXO3NN z@t3MU6ZL$f!7SF*UFM%2UMd{7|K!G~r_5#pt7p{>+w_mG2s<|>>^hd^*f0LBc}1w+ znDF>n&oW%r{+|&r?CqXM_ZejQ>+TDE5OA-xqyVx55 diff --git a/stackoverflow_api/__pycache__/urls.cpython-38.pyc b/stackoverflow_api/__pycache__/urls.cpython-38.pyc index b3689ea9312311ff74055801a599c492255508cd..a296348cd8e564efca467afdf278b08dd601d769 100644 GIT binary patch delta 32 mcmcb}ah8KOl$V!_0SI0Q3n%t&Jl$V!_0SH)Aza&iD$m`9_$yZpKT3nKupEo&{`2zs2j0*w) diff --git a/stackoverflow_api/jwt_authorization.py b/stackoverflow_api/jwt_authorization.py new file mode 100644 index 0000000..7b5fefe --- /dev/null +++ b/stackoverflow_api/jwt_authorization.py @@ -0,0 +1,87 @@ +from django.conf import settings +from rest_framework import exceptions, authentication +from rest_framework.authentication import BaseAuthentication +from rest_framework.exceptions import AuthenticationFailed +import jwt + +from users.models import User + + +class JWTAuthentication(BaseAuthentication): + authentication_header_prefix = 'Bearer' + + def authenticate(self, request): + """ + Метод authenticate вызывается каждый раз, независимо от того, требует + ли того эндпоинт аутентификации. 'authenticate' имеет два возможных + возвращаемых значения: + 1) None - мы возвращаем None если не хотим аутентифицироваться. + Обычно это означает, что мы значем, что аутентификация не удастся. + Примером этого является, например, случай, когда токен не включен в + заголовок. + 2) (user, token) - мы возвращаем комбинацию пользователь/токен + тогда, когда аутентификация пройдена успешно. Если ни один из + случаев не соблюден, это означает, что произошла ошибка, и мы + ничего не возвращаем. В таком случае мы просто вызовем исключение + AuthenticationFailed и позволим DRF сделать все остальное. + """ + request.user = None + + # 'auth_header' должен быть массивом с двумя элементами: + # 1) именем заголовка аутентификации (Token в нашем случае) + # 2) сам JWT, по которому мы должны пройти аутентифкацию + auth_header = authentication.get_authorization_header(request).split() + auth_header_prefix = self.authentication_header_prefix.lower() + + if not auth_header: + return None + + if len(auth_header) == 1: + # Некорректный заголовок токена, в заголовке передан один элемент + return None + + elif len(auth_header) > 2: + # Некорректный заголовок токена, какие-то лишние пробельные символы + return None + + # JWT библиотека которую мы используем, обычно некорректно обрабатывает + # тип bytes, который обычно используется стандартными библиотеками + # Python3 (HINT: использовать PyJWT). Чтобы точно решить это, нам нужно + # декодировать prefix и token. Это не самый чистый код, но это хорошее + # решение, потому что возможна ошибка, не сделай мы этого. + prefix = auth_header[0].decode('utf-8') + token = auth_header[1].decode('utf-8') + + if prefix.lower() != auth_header_prefix: + # Префикс заголовка не тот, который мы ожидали - отказ. + return None + + # К настоящему моменту есть "шанс", что аутентификация пройдет успешно. + # Мы делегируем фактическую аутентификацию учетных данных методу ниже. + return self._authenticate_credentials(request, token) + + def _authenticate_credentials(self, request, token): + """ + Попытка аутентификации с предоставленными данными. Если успешно - + вернуть пользователя и токен, иначе - сгенерировать исключение. + """ + try: + payload = jwt.decode(token, settings.SECRET_KEY) + except Exception: + msg = 'Ошибка аутентификации. Невозможно декодировать токеню' + raise exceptions.AuthenticationFailed(msg) + + try: + user = User.objects.get(pk=payload['id']) + except User.DoesNotExist: + msg = 'Пользователь соответствующий данному токену не найден.' + raise exceptions.AuthenticationFailed(msg) + + if not user.is_active: + msg = 'Данный пользователь деактивирован.' + raise exceptions.AuthenticationFailed(msg) + + return (user, token) + + + diff --git a/stackoverflow_api/settings.py b/stackoverflow_api/settings.py index 7582658..0b1f844 100644 --- a/stackoverflow_api/settings.py +++ b/stackoverflow_api/settings.py @@ -10,6 +10,7 @@ https://docs.djangoproject.com/en/3.2/ref/settings/ """ import os +from datetime import timedelta from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. @@ -35,6 +36,8 @@ 'ckeditor', 'questions.apps.QuestionsConfig', 'users', + 'rest_framework', + 'rest_framework_simplejwt', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -86,23 +89,29 @@ } } +# REST_FRAMEWORK = { +# 'DEFAULT_AUTHENTICATION_CLASSESS': [ +# 'custom_authorization.CustomAuthorization', +# 'rest_framework_simplejwt.authentication.JWTAuthentication', +# ] +# } # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.users.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.users.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.users.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.users.password_validation.NumericPasswordValidator', - }, + # { + # 'NAME': 'django.contrib.users.password_validation.UserAttributeSimilarityValidator', + # }, + # { + # 'NAME': 'django.contrib.users.password_validation.MinimumLengthValidator', + # }, + # { + # 'NAME': 'django.contrib.users.password_validation.CommonPasswordValidator', + # }, + # { + # 'NAME': 'django.contrib.users.password_validation.NumericPasswordValidator', + # }, ] @@ -111,7 +120,7 @@ LANGUAGE_CODE = 'en-us' -TIME_ZONE = 'UTC' +TIME_ZONE = 'Europe/Moscow' USE_I18N = True @@ -123,13 +132,57 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ -STATIC_URL = '/static/' -STATICFILES_DIRS = [ - os.path.join(BASE_DIR, 'static'), -] +if DEBUG: + STATIC_URL = '/static/' + MEDIA_URL = '/media/' + + STATICFILES_DIRS = [ + os.path.join(BASE_DIR, 'static'), + ] + MEDIA_ROOT = os.path.join(BASE_DIR, 'media') +else: + STATIC_ROOT = '/var/www/static/' + + STATICFILES_DIRS = [ + Path(BASE_DIR, '/var/www/static/') + ] + MEDIA_URL = '/media/' + MEDIA_ROOT = Path(BASE_DIR, '/var/www/media/') # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + + +# SIMPLE JWT SETTINGS +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(seconds=10), ## вставляется в exp при генерации токенов + 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), + 'ROTATE_REFRESH_TOKENS': False, # при рефрешу токенов выдает новую пару + 'BLACKLIST_AFTER_ROTATION': True, # для этого используется специальноое приложение blacklist app. ('rest_framework_simplejwt.token_blacklist' в installed_apps) + 'UPDATE_LAST_LOGIN': True, + + 'ALGORITHM': 'HS256', + 'SIGNING_KEY': SECRET_KEY, + 'VERIFYING_KEY': None, + 'AUDIENCE': None, + 'ISSUER': None, + 'JWK_URL': None, + + 'AUTH_HEADER_TYPES': ('Bearer',), + 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', + 'USER_ID_FIELD': 'id', + 'USER_ID_CLAIM': 'user_id', + 'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule', + + 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), + 'TOKEN_TYPE_CLAIM': 'token_type', + + 'JTI_CLAIM': 'jti', + + 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp', + 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5), + 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1), +} diff --git a/stackoverflow_api/urls.py b/stackoverflow_api/urls.py index 5a15d96..12c5445 100644 --- a/stackoverflow_api/urls.py +++ b/stackoverflow_api/urls.py @@ -21,5 +21,5 @@ urlpatterns = [ path('admin/', admin.site.urls), path('admin-questions/', question_admin_site.urls), - path('', include('questions.urls')) + path('', include('users.urls')) ] diff --git a/users/__pycache__/models.cpython-38.pyc b/users/__pycache__/models.cpython-38.pyc index d48c8f2c7b22dac35d349e3f05c368d8b500dec6..6fbc9d21fd9263623baecda437acd3dde5aa3a23 100644 GIT binary patch literal 3755 zcma)9&2JmW72jDd$t6Wnl;kvRK9EgYpk^D82oMxS(H3zmxo}VmsV!Z$hsBCBl2+Q~ zGPBFr5*Wail%|DkB*&f#8@<$r0*YhBlt1LZpuqCF*Pik(^wR#`EU6D$ZbM>c=Y7n~ zoA=(l-|S+wTGsIU=gcea-(S_Ve-Ux~mk04ap6D-VxW<{U+4R6#z_d+8=lxPpw#%wt@F#+bT?wjoRnbMi7EIccO#7|IO~9|Lr+ca#v=9tk(Q|C!jE0B zCqHl_u^0(?$?do+LZ{l$nAN>6nWmL3{ASnO&Pr$vw}#h~z2vLmcCt6zddC`mKHN$U zK;N{IN6GH+h9aLNPlq>?Ju7(z+2i4@P8+$H~9~`AkjpfEdFs6mxh3ItR(V zg$_+gbKQshshVwHnSn(ft7UFjBgZzaH(va*W53-e#`@=sa159xXYYn%ovC~I` z-m#J=WO8QT_VDv$7h|7*i>VHhuag7pH0xx`euLd$g;> z9Yu>jzy0K~g(28(w!?=s9_tOjAfH=jM^e0C4Ca4IK7gNghkr~4$)M3x#>}@3#B%(j z^Fq&gJkf_}`i!%6Q`TdgnQgYk`Up2@3v^D=+8XP#zII3N>vtJ9ZtI^KedA89pS#PL zhMsX(qc@Tv--|J!mE46bnY9SIMe(CRJ%p3Vwm*~eh<|Fd)ow8c4!@o3BSr_w6FBV| z23|*>Vg|osN@$?}l<1~4zxg`3B(j2D6kDtAC&F^A9ylF05Y5fEUl4XI5xAajxt!x* zL`^!GWBoL*WQ}}UTG;4{IVnS#=GDovCp)1GT;JOij#9EKI7&{}jiRfe3ey+ zg}*GT@P@3RNzEe-TIHT5zX$feKWr((T31)y*o*w|6Y=i5zi7>hXgvW~%25D>IXAzDf&@ zkHWDLFVB&mW0rpIxg62%P)_K`f!wDC&-D#QS1o$S^1a;EcDK0-8)L`?CLTWk= zC9313Wye8Cdp`9mj`MNP^+%GTi11Zm7 zSQ}t<_@h2O=kX}t^|dt(MzNj;4suvk)&o_?shSa5A?bi1RCJMi_f=-1Jd=p3vBD~( z=-I5^1EDBKzsaf}27Q6DsL+7wwkmCdhSgxIVBBMJ2Fo6cu*x~)04@cN^9M3gN2BSR z74lhgB>0Y7TEtEjHV{-N|4?v*f{cQyVC=zjxUGyGA^He&)RrIN7=A{@eGf%_FWFb% zwwpX6yv}y}mD)Ry-a<8}+WlzcMu0SwGLTkA01W7IFuVzX{wrM&0J2cQI5H^%1OVX< z+((BTw*qqDOCSV>&{z_~wFJF%t9Ufr9^p7p<7oRQke4nh3SfqxVG_ExC~$oN!C>jF zBY-)a3~^IM|0kyeuet)HSnm0LcGeF=SlFCaAv_`ej)8m+vslTORP*2xx@rtYeme># zc70;%vyG-D8)V>VR@O*2S`B5a%v?D%Q{S99H1kM4-*`p7PIJ9M&70JiXwuU8Raai{ zgwK^j(()X^ZN^ZDSot6fec^T#D=nek;;!of;C?{EtFwTz1>BF7*e++amOE~2mwR2h zLQ_AjEnb`!Azr|n}%sh(t3G8Z9;mopo%=oC=e1QH7lYzC|smL zmv{kHrkGu$f%wawFBUGK`b~7D7r1i6Sr;4f$CxrT1@~fi$rqb7d^mV+YgF@E(9SRU zZf89;I>;}jJ>Mvw9+<_&i?f;20nZ*!^VGhV>gbj)2Ke^KTyFT`N_eV^DCc}U5nU@y zHq9h)8fWA$@sd=PWDbq}CRg78&34#{rMJ{X6<%#F;WI~FQ6!C)1VZU+rzvI^8%Zc8 zi=rUhaU0lL+Rr&oqFN+BqvBnSgB%} p<}cBAliJ8>drr+?WvKicf{2K&1178MbyjB;qpnwSb!+<9{{^8PPW}J@ literal 496 zcmYjNy-ve05VrGE+A0OHB3>X8O4N-3p(0R`7%C*_lErdk)1-Bh)^>o-u(I+FJO$6d z>XoUlz{EL0q9@(?KHYcs-FZ3~^buI{c}TzD{kCA&JOCqbbpnAQh6O5cg0amV;S_G- zVswp|%e+^_JdR)7#AE&)3OifqKp{54#Y|~QQ$1B&0`3$Q<3gpjylXyy5x6>rz)^x3 zN*wMkJcgNL1>W4mZ$}%?&f2~M@qQe-reDx!B6vC1nek_WmP^yA%Y0q)N!T%6LP}b2 zLQJ0!5U+*J147m{6>UYjFv|2UGb+b97tHvgn&;&QlKW6-!p}`?MOFNiQJpJMJ@Vo3 zG``|$sjF3dE2{-hwIZuctTauRP?ry)dLnd{$92=$9v-bW(thh6xN;zLaf2tJZ;sf4 wmh&n~t5VB+7SUQ~QQIah)%5-dY}TyYH2&|{W(StoJ!>yL$5zJb1vv130adSk(*OVf diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py index 355b468..7271e23 100644 --- a/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.5 on 2021-08-10 12:44 +# Generated by Django 3.2.6 on 2021-08-10 13:01 import django.contrib.auth.models import django.contrib.auth.validators diff --git a/users/migrations/0002_auto_20210811_1219.py b/users/migrations/0002_auto_20210811_1219.py new file mode 100644 index 0000000..e090aed --- /dev/null +++ b/users/migrations/0002_auto_20210811_1219.py @@ -0,0 +1,71 @@ +# Generated by Django 3.2.6 on 2021-08-11 09:19 + +import datetime +from django.db import migrations, models +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='user', + options={}, + ), + migrations.AlterModelManagers( + name='user', + managers=[ + ], + ), + migrations.RemoveField( + model_name='user', + name='date_joined', + ), + migrations.RemoveField( + model_name='user', + name='first_name', + ), + migrations.RemoveField( + model_name='user', + name='last_name', + ), + migrations.RemoveField( + model_name='user', + name='login', + ), + migrations.AddField( + model_name='user', + name='created_at', + field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2021, 8, 11, 9, 19, 42, 187727, tzinfo=utc)), + preserve_default=False, + ), + migrations.AddField( + model_name='user', + name='updated_at', + field=models.DateTimeField(auto_now=True), + ), + migrations.AlterField( + model_name='user', + name='email', + field=models.EmailField(db_index=True, max_length=254, unique=True), + ), + migrations.AlterField( + model_name='user', + name='is_active', + field=models.BooleanField(default=True), + ), + migrations.AlterField( + model_name='user', + name='is_staff', + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name='user', + name='username', + field=models.CharField(db_index=True, max_length=255, unique=True), + ), + ] diff --git a/users/migrations/__pycache__/0001_initial.cpython-38.pyc b/users/migrations/__pycache__/0001_initial.cpython-38.pyc deleted file mode 100644 index f694720262455ec4b61c360fcdb4a1b16335a900..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2391 zcmZuzOOqQl5cZ76&-FgDyII0Z5CSnt#=C()LP07o5~w1n6xroq4pZ_-w&j&Ij-=U* z=R^V5y>jA^9QhIa5nVa$l_OOUT9Wrck(nA<-D-79-`6d9XMVm}g6DU=f`6PVmHx28 z=_dl=7JTX^G^9iVUg`$!H*~)tFOQ>cG_G_jfgi7Sg9jy2CehC&647W>`>EWmk>E+G zT{#3FrAO`1G{dNTMXq9|GF1oe1LE8Xd>*PZxUjlgzjx2Fd6wJ&c0MzWhexbz z14j|g^{{(kb93uzg1M$L$rUtxCY4SE9@AuupCz1%fgYM@2gXdu$bA!jeXkvv7R=6) zR8p)dF>@2i##m01T{<-lFlCstf|}MImAy<+=g-t9SgHL?lEWW>cb6u|5o8NgrpYk` z=h=XX!u65sx67u|<5=vPNaUP*+ZI!a$|qFXWfza{QN;!VR-=#}Vhs&b$PS?)RtR&B zz;w)%vPp^dnI2}jM)cW)vy^E*MX)w-z{CKi(s5iY9Xm%#W1TBlMUBut&bc;?A?1@q z(`VW*rfwry&`dQK>}gJm_H7^CM)E5>&n zQy@g4Ork#Br!q$0P;E7r5n%(SVMBtTTb;ObsdJ^1piJ;-eE5q+wQ3fql$lJ%R4F{5 zO0I!gF52d-!*~z4Ay{Wp%|Jh)ylA>UvO8&)wav^DyJUG{7Z* z!}e%FU+MFRbp`x#f_fBbpQJ!A@-t(!BNXK{on;9VN&_J%>mxX+sJ1zP(=^Kkuw$xz zl9>a{Xfn!}prmjD@3RDri)!@lo#>9Vs&c_s#sv{{Uf zQwFkiK=uE!7S2=w{PaDGnD zFcs?=s>;VXbNZ-ACOnszn>y|(ZHvLwvfc;?Q*iV|zRvoLa-v{h;_sRI7z@aEsUEdA zOg-^OSYnz<0vAxuX_A;$l03~ZxAQ@&F~Kw(RHjAfgbG4M%Aj0A3((wMmoyLU)g{Xg zvO8>W8_vA@Hmqsfg(CIc`FnumHXBnfw(evZr&xHYN=8@=GE+-4p(X3dip`XB*5SsE zU@7?DnVlTp9hIeNerYSpJE-KEai}B>0g6meQx@62S$v4abUU-HH=DCwK(qjuW(IWm z+xNGUd|)Hm=CAKN)=G8u;e2F@XM1#O>v{*OXjf;G&SRN5gp jI!NOqL|x1ilzi_i2x97=`^>p%6F}ANzJfZeyk7nnGpzg# diff --git a/users/migrations/__pycache__/__init__.cpython-38.pyc b/users/migrations/__pycache__/__init__.cpython-38.pyc deleted file mode 100644 index 2c6608e600afa06a09bff94c42eae8f8b2c19ad6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178 zcmWIL<>g`kf=hb@6G8N25P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;x_`erR!OQL%n` zMq){3aZY|&s-dBUzDsIxc1eDLen3%vR%&udaeP6gesM`+ayC%DC@m+yJU+1?Q@<3f qGdDB62&gwduUJ1mJ~J<~BtBlRpz;=nO>TZlX-=vg$imM+%m4r;3@;o2 diff --git a/users/models.py b/users/models.py index dd4e152..f192427 100644 --- a/users/models.py +++ b/users/models.py @@ -1,9 +1,115 @@ -from django.contrib.auth.models import AbstractUser +import uuid +from datetime import datetime, timedelta + +from django.contrib.auth.base_user import BaseUserManager, AbstractBaseUser +from django.contrib.auth.models import AbstractUser, PermissionsMixin from django.db import models # Create your models here. +from rest_framework_simplejwt.tokens import AccessToken, RefreshToken + +from stackoverflow_api import settings + + +class UserManager(BaseUserManager): + """ + Django требует, чтобы кастомные пользователи определяли свой собственный + класс Manager. Унаследовавшись от BaseUserManager, мы получаем много того + же самого кода, который Django использовал для создания User (для демонстрации). + """ + + def create_user(self, username, email, password=None): + """ Создает и возвращает пользователя с имэйлом, паролем и именем. """ + if username is None: + raise TypeError('Users must have a username.') + # + if email is None: + raise TypeError('Users must have an email address.') + + user = self.model(username=username, email=self.normalize_email(email)) + user.set_password(password) + user.save() + return user + + def create_superuser(self, username, email, password): + """ Создает и возввращет пользователя с привилегиями суперадмина. """ + if password is None: + raise TypeError('Superusers must have a password.') + user = self.create_user(username, email, password) + user.is_superuser = True + user.is_staff = True + user.save() + + return user + + +class User(AbstractBaseUser, PermissionsMixin): + # Каждому пользователю нужен понятный человеку уникальный идентификатор, + # который мы можем использовать для предоставления User в пользовательском + # интерфейсе. Мы так же проиндексируем этот столбец в базе данных для + # повышения скорости поиска в дальнейшем. + username = models.CharField(db_index=True, max_length=255, unique=True) + + # Так же мы нуждаемся в поле, с помощью которого будем иметь возможность + # связаться с пользователем и идентифицировать его при входе в систему. + # Поскольку адрес почты нам нужен в любом случае, мы также будем + # использовать его для входы в систему, так как это наиболее + # распространенная форма учетных данных на данный момент (ну еще телефон). + email = models.EmailField(db_index=True, unique=True) + + # Когда пользователь более не желает пользоваться нашей системой, он может + # захотеть удалить свой аккаунт. Для нас это проблема, так как собираемые + # нами данные очень ценны, и мы не хотим их удалять :) Мы просто предложим + # пользователям способ деактивировать учетку вместо ее полного удаления. + # Таким образом, они не будут отображаться на сайте, но мы все еще сможем + # далее анализировать информацию. + is_active = models.BooleanField(default=True) + + # Этот флаг определяет, кто может войти в административную часть нашего + # сайта. Для большинства пользователей это флаг будет ложным. + is_staff = models.BooleanField(default=False) + + # Временная метка создания объекта. + created_at = models.DateTimeField(auto_now_add=True) + + # Временная метка показывающая время последнего обновления объекта. + updated_at = models.DateTimeField(auto_now=True) + + # Дополнительный поля, необходимые Django + # при указании кастомной модели пользователя. + + # Свойство USERNAME_FIELD сообщает нам, какое поле мы будем использовать + # для входа в систему. + USERNAME_FIELD = 'username' + REQUIRED_FIELDS = ['email', 'password'] + + # Сообщает Django, что определенный выше класс UserManager + # должен управлять объектами этого типа. + objects = UserManager() + + def __str__(self): + """ Строковое представление модели (отображается в консоли) """ + return self.email + + def get_full_name(self): + """ + Этот метод требуется Django для таких вещей, как обработка электронной + почты. Обычно это имя фамилия пользователя, но поскольку мы не + используем их, будем возвращать username. + """ + return self.username + + def get_short_name(self): + """ Аналогично методу get_full_name(). """ + return self.username + + +class UserProfile(models.Model): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + logo = models.ImageField(blank=False, null=False, default='media/default/') + + + -class User(AbstractUser): - login = models.CharField(max_length=150, blank=True, unique=False) diff --git a/users/serializers.py b/users/serializers.py new file mode 100644 index 0000000..6140e64 --- /dev/null +++ b/users/serializers.py @@ -0,0 +1,34 @@ +from django.contrib.auth import get_user_model +from rest_framework import serializers +from rest_framework_simplejwt.serializers import TokenObtainPairSerializer +from rest_framework_simplejwt.views import TokenObtainPairView + + +class CreateUserSerializer(serializers.ModelSerializer): + class Meta: + model = get_user_model() + fields = ['username', 'password', 'email'] + #extra_kwargs = {'email': {'required': True}} + # validators = [ + # UniqueTogetherValidator( + # queryset=Event.objects.all(), + # fields=['room_number', 'date'] + # ) + # ] + + # def validate(self, data): + # print(data) + # # тут можно написать свою валидацию + # return data +# +# class MyTokenObtainPairSerializer(TokenObtainPairSerializer): +# @classmethod +# def get_token(cls, user): +# token = super().get_token(user) +# # Add custom claims +# token['username'] = user.name +# # ... +# print(token) +# return token + + diff --git a/users/urls.py b/users/urls.py new file mode 100644 index 0000000..f3f31ee --- /dev/null +++ b/users/urls.py @@ -0,0 +1,11 @@ +from django.urls import path, include +from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView + +from .views import GetUserAPIView, CreateUserAPIView + +urlpatterns = [ + path('hello/', GetUserAPIView.as_view(), name='hello'), + path('auth/', TokenObtainPairView.as_view(), name='auth'), + path('refresh/', TokenRefreshView.as_view(), name='auth'), + path('register/', CreateUserAPIView.as_view(), name='reg') +] \ No newline at end of file diff --git a/users/views.py b/users/views.py index 91ea44a..c2feb29 100644 --- a/users/views.py +++ b/users/views.py @@ -1,3 +1,29 @@ +from django.contrib.auth import get_user_model from django.shortcuts import render - +from rest_framework import generics # Create your views here. +from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.response import Response +from rest_framework_simplejwt.authentication import JWTAuthentication + +from rest_framework_simplejwt.views import TokenObtainPairView +from users.serializers import CreateUserSerializer + + +class GetUserAPIView(generics.RetrieveAPIView): + permission_classes = [IsAuthenticated, ] + authentication_classes = [JWTAuthentication, ] + + def get(self, request, *args, **kwargs): + return Response('1') + +## чтобы уж совсем не быть ленивым, я напишу свою регистрацию + +class CreateUserAPIView(generics.CreateAPIView): + permission_classes = [AllowAny, ] + model = get_user_model() + serializer_class = CreateUserSerializer + + + + From d747c41a03c802567d4c4cb7b0176ba5cd2601ab Mon Sep 17 00:00:00 2001 From: whatislove118 Date: Sat, 14 Aug 2021 05:42:28 +0300 Subject: [PATCH 3/6] need_fixes --- .../__pycache__/settings.cpython-38.pyc | Bin 3327 -> 3594 bytes stackoverflow_api/settings.py | 8 +++- users/__pycache__/models.cpython-38.pyc | Bin 3755 -> 4914 bytes users/migrations/0003_auto_20210812_1631.py | 29 ++++++++++++++ users/migrations/0004_alter_user_id.py | 19 +++++++++ users/models.py | 36 +++++++++++++++++- users/serializers.py | 29 ++++++++++---- users/views.py | 24 +++++++++++- 8 files changed, 134 insertions(+), 11 deletions(-) create mode 100644 users/migrations/0003_auto_20210812_1631.py create mode 100644 users/migrations/0004_alter_user_id.py diff --git a/stackoverflow_api/__pycache__/settings.cpython-38.pyc b/stackoverflow_api/__pycache__/settings.cpython-38.pyc index 786c1044676205b7faaa93be3260bc887594cf59..0eca91996a5276feb45121585b809aae7a6dd52a 100644 GIT binary patch delta 591 zcmZvWTW=C!5Qg_#XbF^}m2;u=e6FnLL#+o|4id36u%yW(W~F^Uw`(ahutcS4deJ+R z8p*~xF6?h0@xs60mH)&T?{PtzXyUw?%s1~dGx<8f_hDCIc-SGBkzMf@e|Vd&Fsn9~ zU!1_LI>`kOyzs$~0D>4*ZFC7Cx{NTlV=N@741 zNvpM+mW~C|0f$zU>NQ@iN#L)F^^z`?DrzNqSXLXpKlH*sI_@E<;oZ~q!`iAOshYl5 z--+&44y2>whVR1G-)Oqdt9{@2U|VZ{v%MABd^_%_vX>N$Cz7#3Mpg>>L{8btWs~Vl zLdj%PSqf|v@^be1e~3GkmY){Zl}vi`nX(m=y^?6uc*i3iU}q&F3 zAZ%gpAMg*@+KXT*`WZx=;qjPx?+tTfe8v4onx;yko&w>s_fW@g&}pZ1(zJZ+M-U-| z5kV9&#H|4yMuG#-%|RHtWDz__B84Y!jBmn;tBiD&*f@!7A2J#X2^yi7nKGcN;tZGP`Ow!a2x? yQen@zCq;Iil~2X4c&oJUTzIc!$~&)WgY3tlTY9h$w4(Ci3fR}$F}dv*t^5s+0b0rc diff --git a/stackoverflow_api/settings.py b/stackoverflow_api/settings.py index 0b1f844..c1a44c5 100644 --- a/stackoverflow_api/settings.py +++ b/stackoverflow_api/settings.py @@ -38,6 +38,7 @@ 'users', 'rest_framework', 'rest_framework_simplejwt', + 'rest_framework_simplejwt.token_blacklist', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -150,6 +151,11 @@ MEDIA_URL = '/media/' MEDIA_ROOT = Path(BASE_DIR, '/var/www/media/') + +DEFAULT_USER_PROFILE_LOGO = '/media/users/default/logo.png' +CUSTOM_USER_PROFILE_LOGO = 'media/default/{}/logo/' +GITHUB_LINK_PATTERN = 'https://github.com/{}' +TWITTER_LINK_PATTERN = 'https://twitter.com/{}' # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field @@ -160,7 +166,7 @@ SIMPLE_JWT = { 'ACCESS_TOKEN_LIFETIME': timedelta(seconds=10), ## вставляется в exp при генерации токенов 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), - 'ROTATE_REFRESH_TOKENS': False, # при рефрешу токенов выдает новую пару + 'ROTATE_REFRESH_TOKENS': True, # при рефрешу токенов выдает новую пару 'BLACKLIST_AFTER_ROTATION': True, # для этого используется специальноое приложение blacklist app. ('rest_framework_simplejwt.token_blacklist' в installed_apps) 'UPDATE_LAST_LOGIN': True, diff --git a/users/__pycache__/models.cpython-38.pyc b/users/__pycache__/models.cpython-38.pyc index 6fbc9d21fd9263623baecda437acd3dde5aa3a23..bc9ee632e4a27ee0b86d4dfab61f49d77f5a7c3e 100644 GIT binary patch delta 2112 zcmZvd%X8aA9LKGPZP}I|ahyj>Lq(wvLmyB|3j+g9)3}sLlTKq_G{b0=>^e~@Tj^S& zlo@K8w8McGrZocxE@g&GV3?D(Q4Gg6pGK2h6#Vo0%QL&o^KDe)v>`WJvaEgk))QA-^o?1tLsGin%+FZ%e{T z%aY3@8H{3Cm_S)H8;y$&BZ2HSC|ilJp?iURO*oe0l5H@$YBh|8w@4Wm1PYH_vsz_& zuIT4xsB4B>-^D)P&WEuVy2;+|1M#E6Ppvg|S5qJ|5lHlgq$jAfkc2Og*bPxnAyVPT zZwPui^u^H6z|SJDAfMat6Y%>;QqPkVQRhUxpB9!Q`T$9j%+-iKNU|h{c8K(mJX&6v zeo{bX3d`bQeH$4-Sq1~Sg6}GqR-_=c$gG;lE*aw-rO*TDnlDeL*TaIJ^A zNai!tA{f;W5i0^ajApX9y?3_Ohw0t#CdTGXR66C=qFFAxtc;65Q4H*P7>9MDrg&{Xm0!RrBw*ulUWi_B9Rds{coO3A$_L z5_<_#7o{LNW1IE!fm{cDLBgpUgxb`lz~MLqY!oI)c#F1U5|9vXh9{51p-%;DFPH9y zc|u?&i^ILEk4%&8Ux;%Bps7#NaGtQoyDxIDfHzuY|O$D*4!)m4*Y&$t#8m&x}jY{)*jV{~H zoWqWV53-$E)3uy>kSNnn-S8Fks5#?!ZV+`X*QQ%?_5sFTz^}niNJW%|yigGHg8Xkx z%n3Px@%~NTn(#YU7dVFadEjUad`RFT4&>wxav?EMoR~@E6Wu8FOtcAN3@2ppyINqk)oj|DM0TUu%CE`ghu2ae(go zYyLw3wA8+?H2})2YcOh?E(LTUm74z>DC6!r`*UP1%#CG9n9fD54 zD~dfd6_J=M_C3c?4?-nAme)6kkBv@`jh-CWRS&zySnO<@K&hOY=&Yl9ky152~ksf!za=O<~$5 z-)rGPtOznF$q2YbRZxYnyEwp(w0=#moz)-?F41IBi2qqw=U|-3lrs9undu0hO|#szkFf3(I9DX{b|2;{;R? ztq^6|MKuc$Y*@Bp1r?tG5@I*s(2w9=Q(YKjbNSqWI1?`9&kXc&)G0ZP0KBK$^WMOmHL;(6Gl9$a#7Xk>^gZLo_72Q2B_LD@RHi-G zDWNJ1ZC49&5W{id)pymvfXD=%+a*CEQb))WQ2Oqld9C4U}{A)%-PZNc;JfwK9L4xt!NPU7sXq%?wquX zkHECpF3gBOW^WoBctCg+*PZeRp)^8h5)Z?thwZ{=GMg2c8KSe>tRJ=paU5<$T^5SD z(w6U|ZkX6Xak`f9ex`1V-=(SROa3T7iz_A(>If!)EIe3?_+p2}l;iHQ_^2Co;(rN8 z{Icp~TpU@!)mdCIhcJ)u-$%x3n41DvfRW<8nqteY<+I$gy~;SbB3>95wpF-69qvX8 z3N#OmHDn1JyUdeTCuS>)z9vgO-swhsGhAnzd>SfAlhIB;T8-H&rwcS%IBxm^sB^1v zw6QMr4d_j#Uh<2>eKwnohvJh}yI*W{qc+PN26~*dlc8p=!Ok(7(a{X?2*->+!f%Po t-j4=)mAS_WWpOq!tcEmicN02@* Date: Sat, 14 Aug 2021 06:06:39 +0300 Subject: [PATCH 4/6] fix_bug --- .../__pycache__/0001_initial.cpython-38.pyc | Bin 0 -> 1349 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 0 -> 182 bytes .../jwt_authorization.cpython-38.pyc | Bin 0 -> 3475 bytes .../__pycache__/settings.cpython-38.pyc | Bin 3594 -> 3599 bytes stackoverflow_api/settings.py | 2 +- users/__pycache__/models.cpython-38.pyc | Bin 4914 -> 4869 bytes users/__pycache__/serializers.cpython-38.pyc | Bin 0 -> 1537 bytes users/__pycache__/urls.cpython-38.pyc | Bin 0 -> 561 bytes users/__pycache__/views.cpython-38.pyc | Bin 0 -> 1727 bytes users/migrations/0005_auto_20210814_0546.py | 36 ++++++++++++++++++ users/migrations/0006_alter_user_id.py | 18 +++++++++ .../__pycache__/0001_initial.cpython-38.pyc | Bin 0 -> 2391 bytes .../0002_auto_20210811_1219.cpython-38.pyc | Bin 0 -> 1391 bytes .../0003_auto_20210812_1631.cpython-38.pyc | Bin 0 -> 1188 bytes .../0004_alter_user_id.cpython-38.pyc | Bin 0 -> 668 bytes .../0005_auto_20210814_0546.cpython-38.pyc | Bin 0 -> 1206 bytes .../0006_alter_user_id.cpython-38.pyc | Bin 0 -> 654 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 0 -> 178 bytes users/models.py | 2 +- users/serializers.py | 18 +++++++-- users/views.py | 8 ++-- 21 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 questions/migrations/__pycache__/0001_initial.cpython-38.pyc create mode 100644 questions/migrations/__pycache__/__init__.cpython-38.pyc create mode 100644 stackoverflow_api/__pycache__/jwt_authorization.cpython-38.pyc create mode 100644 users/__pycache__/serializers.cpython-38.pyc create mode 100644 users/__pycache__/urls.cpython-38.pyc create mode 100644 users/__pycache__/views.cpython-38.pyc create mode 100644 users/migrations/0005_auto_20210814_0546.py create mode 100644 users/migrations/0006_alter_user_id.py create mode 100644 users/migrations/__pycache__/0001_initial.cpython-38.pyc create mode 100644 users/migrations/__pycache__/0002_auto_20210811_1219.cpython-38.pyc create mode 100644 users/migrations/__pycache__/0003_auto_20210812_1631.cpython-38.pyc create mode 100644 users/migrations/__pycache__/0004_alter_user_id.cpython-38.pyc create mode 100644 users/migrations/__pycache__/0005_auto_20210814_0546.cpython-38.pyc create mode 100644 users/migrations/__pycache__/0006_alter_user_id.cpython-38.pyc create mode 100644 users/migrations/__pycache__/__init__.cpython-38.pyc diff --git a/questions/migrations/__pycache__/0001_initial.cpython-38.pyc b/questions/migrations/__pycache__/0001_initial.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af6ceae16e9824b94b654f24fc68120d0a0785af GIT binary patch literal 1349 zcmZux&2rl|5GF`Uq9{ss9OuWKP7b~4BHFn$)9G~LN_OIDZMU_2;RQnpD;gB|6N0j> zT-&SPA-T1W&{x5=C*ON%4s92t6g$&`1I+GXvESm`1<$)(*TC`X^;YnZQmL9r#z4rEsrI`+Hc@$rQ+`1V1B`$$BQO~WEU@1-pc%K` zlZXTk*m0Yg%mO#=FoGXu!J0Sr%w#RJdCXz$8-kh(?z`@L1Emhyd+6y^_AY80tj9Jg zZ4SVcDpuc?4EDlb%rft(gR zuTVUOG1sBdv4%>sD;hGU8kZcd>ZuONyap3!$7ht9!rQT1#@UmQMOR%AwW0 zC{-?{*n0~BD0`H?S%g9(q1NIlFOiMH($Tl&RhZ}D1RWXVkTOW8%fi%K8~f+u*Yy1C z;3s-~Iy(4Xc^^GENYxouR3GaOFZ7F2-nTs3$08i+%c%D7A}m(o7_Q4&?2eGiF;AdY zy`!{*2v&aXVO9W-((kZlO%{h~lqr))jgepAGj%2Z)tr0>X3^^)!WXhD)uw zqf>fvI(~h0@=Cc`4y)(*n^Am;c~;8@>YrnMqGRyrRiY$g{ zDQUj+Wf@NAxL?eKu6WMOAq zadGy@vk&IqcBi)0mLB<>Jo^i+e^%%F4mM)N!(f`Fv$`(rm4!{J64u=Bd^8T~f6idd iS>fwD>um0BUrR60rktW9 literal 0 HcmV?d00001 diff --git a/questions/migrations/__pycache__/__init__.cpython-38.pyc b/questions/migrations/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06255acb8c312fd30bfa644a3de73964058a6fbf GIT binary patch literal 182 zcmWIL<>g`kf)y1)i6Hthh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10cKeRZts93)| zBe5j2I48d>)zHvF-zBv;yClCrKcFZ-D>b>KIKH4#zqlkZIU6Wnl$MiU9-ml{sb5%{ uT3nKupI5A(o0(n&)DL3D$7kkcmc+;F6;$5hu*uC&Da}c>16leRh#3H|6)xpth-m;EhZ2$XlA$#7z_TFU-E~D^L9kJn@}bJ6<^UXQmS)Usl z%SyPsu>;oJ3zGB?b&{8c&I#Q9*Lc{HEjv<8F3K{s6-TM5MYX0CHPKfcy_PDbL|b#x zwM;Q1+PX7R9KrmQldX*wM`h_#$xhpu>yn*esU@|Tv-LAle&jJcNO?KR_$&y@^$UJp ziL&fUi8X?E)U zaQollVaqMqlmdB0Y00bdin=OYQ(96*ThY-{TZ;dNEuWEsR7+WsZKbMs?trR}}zHHQ&%BDQomD{u^(Hi@eM4 z8wpyO!Pmo^d;|A7U!xh}LU_mEo9O(_?_>CZ5q^ix#$khR^ETf=d!2W}1>WIXyle1o zxM&Ew_jva(TA1DDcf%#JHE{lrcXnnO;cb|@&mRFyhi_v&UkjIDqfH&yzK&r42!Fu; zPQiFHiT6!IIBt`914e)vTY#kvf&-f#dkqI_)9+iFU}hXo7+H+Zeh*PT}&- zdpk>rucLWm#;r5sh(Xi)4u-76698j@)8>dABmAD|Ab@*piM9h6U4jgnZV}OiA+P)o z5O))pwn1!on^*<+%r?N>WD{wA>xitU~r~L$oKLL`?wk^PJ z^?-03uMyq>_=kA*;zY#68hMuq)F!4b$7cYJ zhq<6YgHMo4jCJ|uFwA3l+wXRaVbG^QZ)hEq)jKqC=;HST;obJq&Mw-`<%3 z8~Rg3FIE8P5F#-wwlcIW*n3Ls65B*gmp=dj6lWk|3H&?)e?QV87YzREAbt=;$WFpY zF}^YEe86g(ulG)I0rT$?g|T^X|9>$P!+~+c>5rfmxkHT(%pl>gFJM4i4Y>x;jyNNV z0Cd`WrUSO}Gad0-%ylvhut3DBa85x-c7*Bx|2l|4wveDCq5+87Lm-CrH&%FomPBMj z1PHPamQJ2NMZSq|Y>)Dcd@T^_uJFA^XH4Yt_8_8W9?KBy$0X+-wdVC^Fni>9ek9T; z$UM^Z=+Ffgn50FnSDqIY$-Kxcn|YD$H=J@1y_^s#)T`cGv*EGX@|8$;+&Rou9afK0 zHY>R{izbD=UWsF7$zwKkEXU8MBF$&cY?Sucr6%)(Xq2q?Y!)XHoxX!q-;v0Oza(!G zsQGcihYD=+Wa-Cz)Rj+{V-wo?Bt1z&9ILr~JSwRq@`N1ya*$l=m2^ z%soLtp>Z|JCHBq6;M9K^4{2XYAD6R=CTmJg5qElA9;dc8|LU%qT1XlxsbrvcQDM#C z7KL>gjroZ{T9I2ypj6aV<(hh4s=ua5fmY3W@5mDU*(jBPzLIKbtMa1!l~h;0l;#fx z=}M+D(n6h|lx+33d`-v7*Re8P$zpAzw^rM|wxw4_{U2;S`KG0}l-an@;;Sc7X#YfP zJ%WxeQcmqr2xvI2ZHUxZBH9Spet1G*g;=1FL4}c!5KqKwubYsJVJ$I^>?8~&6?A8t zgo)yxa%8vAL7jRvS!f+4Kir6t2r)&<+!HX!(oo&Pyxqw3|#x1?|<$L=g#>Bc*KPBTs2mo3rGTc;CIvTeOuf*j*H~P{l(F)GXtB zpo7nwKEIf>6)q(`EcN6Ltn?+k(ENy8{jzf;Sid*D;GH%BJ%qmweD7?8Zx`~pNJT1n z6ENnH>O|Qy)1RE4K5KqH{Z%wF-TwymC=WbJ0546m((X4RT_Y7*6y;93%%5?C=__UE z!${dTtx{0F%xk3(Wz!@BCYmK~`z|ALpJaT164@glYGQ$YFyF^weR z#aD*kBvl8J?cs}ADo#EzXYi9GK8jZ{Dauh{@C(=wb9`|+0?uC8qs;s9zCWPa;uHNj MaGJwkM#-uF0p8CY#sB~S literal 0 HcmV?d00001 diff --git a/stackoverflow_api/__pycache__/settings.cpython-38.pyc b/stackoverflow_api/__pycache__/settings.cpython-38.pyc index 0eca91996a5276feb45121585b809aae7a6dd52a..d5d6230b8c2835f43c758f4144a8149b555adb72 100644 GIT binary patch delta 374 zcmYjNIZpy%5Z!OVMPNVfdzbrA4i(p1LA{YmFnoVz4pH6wcSHQ-5hKd834a9E5~%oB$bF1VqB!vimT z@FRdALY7J%gb_g$F~pI8W;w_UoqR}|PNX!+Vo;Dq23h2gx9n|(!pJV>`cb3+N>~uQ zMNL9^B)1s_Er~*?P#9I}MxansL`+27ba%c{qXd>nGuf^FI$f|lmc^*lU%xVzDSekh zoigT}!0WvkKGRJ5)t?*4QDuN>JJBnLrVQi)|`EG8ou;2ltpfe$cP>P8pc9uMo zz3~bBHO4q6lgY`MGc%dT#6!Zmwk)rqC z8!Yt9x{{FI7^WZ*79~p4Eiv3OsdLI6YkX3aX-X2e)otP>sf|m0Q;$mh@#VfL>AMtV z$=JhMFSma5AI~>mX=$B`%&;o6tVx!2$+01Mdx%Z8+Dg}LcG}-ZYwWUXdoh2p$36!f wQsszaYMkiiQ_lXG&U;ar!@M#I7lT*zqz1L2XOFw0-`c2j-+lMW)x~=I0_byG-~a#s diff --git a/stackoverflow_api/settings.py b/stackoverflow_api/settings.py index c1a44c5..db5fe82 100644 --- a/stackoverflow_api/settings.py +++ b/stackoverflow_api/settings.py @@ -26,7 +26,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['*'] AUTH_USER_MODEL = 'users.User' diff --git a/users/__pycache__/models.cpython-38.pyc b/users/__pycache__/models.cpython-38.pyc index bc9ee632e4a27ee0b86d4dfab61f49d77f5a7c3e..0570333fa55d8b93d7df23a838eacb39f8ac63ca 100644 GIT binary patch delta 486 zcmYk0J5Ss|6oozZV$ZHU>$MjX31t(WD@;H^kv6^VFs z+i+><=prbPfL}ltDMkA2Dd;JvQ0}Y{VkDpW&bh}|b6Y+xi+Le(8lB%mAL7*;v1%Qh zl1ntnK$Ci6tY?6MPM=XXWD9wdm_eqlON$&QZmBbwZL-0ieox@q)7j)4h z(;kvb*03O1j(4lI>APS2L}wv#`@;O93L#$Gf2|?HC~U)@P8;4jXT^Rs8c;H*M2+#E z8{n46n(bt`b$1}j>{Dno?45LNGfwvxHcwJjEwuvN0 z4^(fxFyYR@3rFSR)p*c^FF@8$zz6VZe5NsxIsBgA|9PI-?0l$xsj>!Ru7PLaMmb*l z%+~GqpD+o76EHXx=4J+n$ZlFd!R(vd#*PC7unSqtIm|9P0jp1W9#a9`?i0=iP6u8@ z_pt9^zx2;@=svhSfIJk|C?68xuEERDU{LHCyaFDSu$}`S0<6PN4H$y3XF#}1`3RJk zji{1l8n1L`E9xJDwaFVEwPi@AXejU(n%cw8=ZJ15h`>hN>zNBoIo5Bc?HYS zbLS%^lj_7hux{zuqwx>`Rqw{L1P*JDF3rZCBOE>lSw#FTeDdn`D^1w$ei-3K zU9VnK--}m6c~ASa#*D@+LYdwha$mjm9+H~+>Rm)WV`J*K_haMIoPIWzGeMF8cg1Rm2)QKFUJHk!9$TPYt{4|IHqkAGuOHqkfoJ_5#{Lx}Q3+^ozaIasPI#Cro zAuEBWH22h4`P^z&e#85$CeigPp2uUwWt?V=iwB}>DIM^5M3uVDB!iF&oF-Hx6D}2) z+ZV&+dd$CMaI?qdS2$rb&m=}(K-o-*4_c3f0g2=7!WJ;hz zWb&ijn6FP%^%@4Gf$iX|ae3FkBwFQV%;AVin$DsQO&D^fk#!r?gsuW-X&i#T2e<$R zrKuzvVl2>Td3Sk3I*=ID;VLe=atn-AALRy^`XwZX)LW5t2i(e38cg;INB!&yj8;|= zyoLfhX&R^2+OlmB(EmA_w*jq=(L( zr_R=V@EKf!|FEU2=5uP9PgO}%{~G$&PVhIl8i5(CNwcUP9lo3W3f|*n6w;?k%wtz= I-&x=L2g6u%4FCWD literal 0 HcmV?d00001 diff --git a/users/__pycache__/urls.cpython-38.pyc b/users/__pycache__/urls.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb13081f826aef48f7573132922ddd472a6c4d03 GIT binary patch literal 561 zcmY*V&5qMB5O)5Ww53&6h%5JAYV8dngg~qWdw~jA4!%UDo;GRiII^7$+jrm{;K&>B zEWUEuS3n#XXE`im`5S+q$1~%(S}bM+?P>go|BMLv707)nki5WczaR)AB1u%lA{DbZ z3OtsHN?EEhmLX3>Dkmyuxhhx@5r{+v`M2qJA|@jLnjkMA9r^ShpF#E?pF=V72jPC7 zvYA+XAgkpqRwt|2ryX~-&zp8DdjTjs{HTx6zWeNW({6ZUJ~c4-aunag&Va3ha*JOJ z&zG;kU0EJvP^UCsSm9C*9e>)uFfVytTt1ojwvan;UXvO$|;WgFE=I1FxmjSX6phR6)TXLmv# zgfM=eb6W+?&oL(s0L!)Z2Qg)c2=Mz24PUTysJUyb)You+{)AqDJv!adjnN0#I$L!& s)H=RB;=S2PJyg7FXg|IT-LAVEUp!M<^b($jiPXxbAKF{ix>lLBU#OBtmgER ztmh5ZaC$78d5g82UY48r7Ta=qMQ-OiY=@E;gm3Wbd%~+C9PM8FY!8qcuLDvCzxLPsSuqB%dLo8O=(B!tF3{d`%F8z<&Bn)R zrhdu94B(B|5YVwIhMB~rwx22iJ0SQ9;z?z8CDZ^9u--f{o%89?n43sTYn)8E_rx-gxd~q{-=hdqWu!OjzJh8_L{;xuV?9jLI{=!w2(tv zQsV7YXk&v^okFh8XZZg>)DDdL=ctRD=x-UPDXSdaC$@E zh4XOaagX~qR6Ux9zx#g>N=yJKG2tlU!HoyZhCL{?fTt$ygVIoGrbQxt8;FT<#jD`< zlXgixfS+vwGs{9;q|U~fPA;G{IaEaoB$i>An_`?I)h?tRQ9HW^|RQa zx%B9>LYcwTXywBkTZdP`Btr#tIxEziTvoNJ0mNDhXvL~_ z>9&m%0jUxfVp-GfzS!D=$xj&OcZ~^04ANoa9~Kw;M+%lk2uq>qHC;(mJ@{zV-z@(N DPe;Fg literal 0 HcmV?d00001 diff --git a/users/migrations/0005_auto_20210814_0546.py b/users/migrations/0005_auto_20210814_0546.py new file mode 100644 index 0000000..022bda2 --- /dev/null +++ b/users/migrations/0005_auto_20210814_0546.py @@ -0,0 +1,36 @@ +# Generated by Django 3.2.6 on 2021-08-14 02:46 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0004_alter_user_id'), + ] + + operations = [ + migrations.CreateModel( + name='UserProfileContactInfo', + fields=[ + ('user_profile', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='users.userprofile')), + ('website_link', models.URLField(blank=True, null=True)), + ('github_link', models.URLField(blank=True, null=True)), + ('twitter_link', models.URLField(blank=True, null=True)), + ('website_link_active', models.BooleanField(default=False)), + ('github_link_active', models.BooleanField(default=False)), + ('twitter_link_active', models.BooleanField(default=False)), + ], + ), + migrations.AddField( + model_name='userprofile', + name='about', + field=models.TextField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='userprofile', + name='title', + field=models.CharField(blank=True, max_length=100, null=True), + ), + ] diff --git a/users/migrations/0006_alter_user_id.py b/users/migrations/0006_alter_user_id.py new file mode 100644 index 0000000..13f634f --- /dev/null +++ b/users/migrations/0006_alter_user_id.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.6 on 2021-08-14 02:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0005_auto_20210814_0546'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='id', + field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + ] diff --git a/users/migrations/__pycache__/0001_initial.cpython-38.pyc b/users/migrations/__pycache__/0001_initial.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2bf720b5e164fcbc7e2d883cbb8b70761118fc7 GIT binary patch literal 2391 zcmZuzOOqQl5cZ76&-FgDyII0Z5CSnt#=C()LP07o5~w1n6xroq4pZ_-w&j&2N7C%Z zbE1IjUO90{xbc^C<+N9hR6%HIybp@Z)X3^qt6TcMZpl0I^UV@Gzdc*QKhBj(e>mav z6M=9GK7A7!QX&B_bp!t!`rnY3$5A&LSGtv;7_WAN2PIM_(a$9k(P&irsobrR;7O@n zIRqc2NA1uy$84amVNz&Y9ZN#FPTkn)X9I*=@abMqDp4P`8G);)QGCDI_B_EKBe(i10Ho(_9`OwRkKwbm+GPy!x(jk|~ zreD|AOn=quKO!F&`oRKNU4zJ<{8}cT&h}J$zW$=r2NcQmg9xxZOKt!=pV`L4BUZM7 zqX=ha*uAj1xpg(c+)$Nd8k#;++9U#xX)?yo5>Cay3~jUnV>V>uz74;=*N$upX3Hd1 z6dOwH+(fZ4R?}pcPHh8B8RjgfwzWr9PipG@+4=-)y)P9x`~i6PX>uGvwLoQ?97Av} z2TbI?k9@yfwv`^oV%J6@)Iwthgjhh z2+>F?)TjGY#poMqoaQnjY`_d`NDy?Z6L&6ku5=P41)s);zc^H@c7ZA-RWhbp;{nxb z4b*DUHD^7>d%z9BMk+l6{e<$o>HEm-q+M3a$1^=U4bP4n%YE0I*$N$F#t;7i+kD>l z5hg@IbX#{68QkyZH%`&BKcs-LaxfPVrC2zg5ferhykRnC0%>MwoVUD(83(ojE&&|2 zM|1j0pGT}~;FlBBqsSCV3IwBKW{h@(rktj;EMY<$AOy)if|H6GmjgIWWhQ_fTP-Hp zIlzo2Bgq6Mxff6&v_rM(fbtksii8bMu(Q>HlG#M(cpElc^ow2k?Ceo4#Q>64#^^X@ zAX^92{4ZgP zi@IDnk|1xPhJ6}`kRN_SOU_Yps&?}8PbM^FeU|>GqWX}l$2Aw{i$3z>Z`#5R)zE})FlB(bd|d75GF=7UsYf*CldY>Utd6@-eELAitupt-v~X&$<(OO-uj zci7-IoO$xz;z(u)#*?XXeFdzc!>Am-j4DwOhO5C+umbNz-@4vPunxM7VB^nl zISk_&S@)sCrIkJk<9UBMVfPDAxQT!D z6)xZbQC{YDsz^>Vn){hgob0P053`VXKX?#8_=^Xjp!4WwKZ}6e_tI#E@!s8(+9a1V z&5bOJ%0_t!LRBfTer+Zb=d$}9qi_@dDj=RGyo`XCQ6Mvt`68HyKqVGlQp6F^85VAE z2PlLPUE#O&SYVei53_SjGG7YZycRfjOkZBx41&9Be#5p zi@f(I^{~Z}c_E8wiKY6yHYF>{r;G#G4u~nQmAR7!dVv0I^>8YM0=vJ^0#=G;bgA)nO3c4fu* z#K;Sg5`EQ0$Ec|cpH6M;_;j?aUZLS`dT3+Tu)>&47{d{+l|bBQ>`Bd)^K=r3g}{2n zM2bpNm-672GD4p@n(wtuv4>mL*=1jT5_x$c?lkw0Zviw&`!2=cHeUUK%r{oYgh5fe zcWRR+TN{{s?{44X{Iw?*~Xl#Ahyx}1xNso3KA5Gk5GM!TLW*Up6;HX}LQKJp8l_N2qpAo5Ulq%<&FOJom?mM-ymvYNb=u03)#CwTiq6+ z_4nokX-AK+zU{)C7qjvN9yR@H7|)K^%GyX(oj9&vlts&T6TD@uMPIl~@z?ECeB+u{ MMecHBpY;9z0Xq$T#Q*>R literal 0 HcmV?d00001 diff --git a/users/migrations/__pycache__/0003_auto_20210812_1631.cpython-38.pyc b/users/migrations/__pycache__/0003_auto_20210812_1631.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c37c9f734e97777034c24cf6a031dd407d94bb3 GIT binary patch literal 1188 zcmY*YOK;mo5GI$TMCxHXcG{#s+eTtrX zwaM)bL9fRh-h+PXf|m|>pSvjD#$FLV!03<<`G}7<1pOWKN0{G5+1pqcAs88R7k1L! zw4d&!w_ra#;J0)xw)y^s#3Z`S53rZp$~(D!ICkMQ704>OGo4Onlr?ohXVY0YeGrB; zoP|FqTj#OP)!&?Dpd83pA~0mP?rxJOFB_nB5ktKOsfG)z{6!Y4M1Ud*e>V4R)#tEc zji{9iJgM0^riP_VGA1wS1zai*_asatSDVKwOO7&O(rm(;vg-c3&kPLpti5cPdE zc%HEs+Gdsabj@UEj$h<3FHm)EubY%2{9L(h7f4{`o*m8U>EifU5`D$)lg0dJx;Q)f zm7csfJUUi`qJ%Bi|1#tRYg+a1D$rn8!K*b+uoA^@5QYzeL#Qt5q70A(DJ<)XmX|?Q zv*iWmNda8N?-r6>&^-= Vrrd`eypJ@1m5XYGPjOAx`VU$=U8w*7 literal 0 HcmV?d00001 diff --git a/users/migrations/__pycache__/0004_alter_user_id.cpython-38.pyc b/users/migrations/__pycache__/0004_alter_user_id.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8bc2285de83aa4b6a82c3b9e60b4ad71ee32516 GIT binary patch literal 668 zcmYjP!EVz)5MA5r#&)SxaiD@f@FkAZ2=#!fB2`5ksE{BRUsl`9B&@TE&8|%qu5hFu z!cXuad*#G0AfYnrg4(g>X=moGXWrQJgM*BbeH$Oi9|2=OeelpY1!v@TOaKf5%{D<5 zY{DuGd>rbiie52@fPZDcF{t^MsNxX5V|o0G?yx*`*+#95>{PS0Zg0~7YJ0ixwTG5c za7J!t1jwoYSQSFB3aSWs9YY8a?$skq>J&J{e4s=8&TJ|w`i<8 znoK6gLiSxFrjuzoIVq>2e12Ry?&~g8aPdCpZUnfLz3yCspgMV_(e1ZJZKTM?G=z7!kNpO7XK~tJ2Ov-I>2vP%)Q>?`U7p+>gE%c zYyY?+3m+J)@jUUfk{J)C;$s Ib{HhlUl@S4qW}N^ literal 0 HcmV?d00001 diff --git a/users/migrations/__pycache__/0005_auto_20210814_0546.cpython-38.pyc b/users/migrations/__pycache__/0005_auto_20210814_0546.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9601d6f719c21d260078c428946413ab60be19ef GIT binary patch literal 1206 zcmZ8gOK;Oa5VqHL;yn9;mP(wFa>=7=Q4a{Uq!c01f@pimWwq%}5<43^tT#>5D_rvf z_zC{+E!v~Yc{Z?Hqpvc4IxxLgE#c#=92ZgE>! zBfDddNQc-46XA5+R~C1;`^n-i*rE5)>3E!+ST*k&eXJVM#Zl0gOa*b2=-epgAd=&A zqgz~M1bcXruSme^*xc$6Zujku18#^BxdXW{4}Mq(b73(oahH2M$MbWyN4Sr=GD=)t zm=nas|8VI)Tt-|$|H|A(>*_yfX%Y4Fe0ff=f+}C(tEgGR9BX(U%pLx4ZfY}{b<`}Q zbmLyrcRDNl5%ytI7mn^4fZgyW3CKjRHk-|D%7g+*jf4hVub(0FPR6}JKs$~UJ6Erx zUaZTh!8lW#9$u}aA?k+S3Tv(|#1X~Tf&yI{%V5Ohj1FO@3uqNE5nO>L3S&*7n*<7| z2%@1Wrz==A)NV8pLYMl18ce#WPM6g*P^LU%sn-_$C{`9+K+V>94m~yzO0O=s-m3N5 zVuU*%g1OiTbgmbG;E66R{D$^eH=d~L8=QffBdhqq>0y^tK-5!AfljOu>=K zAsr*Byp7;AMsjFM);S)ss2^*>yV_4%j-##f?fsMX{=rM_pS^#R8J1tfu>clj$lvEY z;|iy6sczZ!fXR$4#$&jBCSNSs#KbB2*=wBP6()`80N+p|;tOcCb{hwf3{^aC;JAcv zt`a()H4>bdA?jsM#8b+~K_eZM#{K(i;MDCI%YHqcfyRB{7+}VCwAJ3$D>v=qh zN$or2#`RpAkjM6Nx~n$sALO@NMk(&1UuVmxx%#{ z!igjQ;wvY90ST3H3Tnsl$TRQBkx+3=+b$>} zD*|9e2*ENaIEpIr18`LBfS?t@2zKrS#CM$V7!n$my5#NuDKs+LSTwen=6QY~)uwOd zB45n&qxrtf5B3k8@VE;#d^mUEo3oj4vz05{x`en|)%r8K@eP`* z)}mai24|e4c{xMngzvfNT4N0tv&6-6=u7ERDT%kKkg`kf<+ZVi6Hthh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o10eKeRZts93)| zBe5j2I48d>)zHvF-zBv;yClCrKcFZ-D>b>KIKH4#zqlkZIU6Wnl$MiU9-ml{sb31# qnVXqj1k{_KSF9f&pP83g5+AQuP str: + """ + Hash value passed by user. + + :param value: password of a user + :return: a hashed version of the password + """ + return make_password(value) + # def validate(self, data): # print(data) # return data @@ -41,9 +51,9 @@ class Meta: model = UserProfile exclude = ('id', ) - def create(self, validated_data): - print(validated_data) - return super().create(validated_data) + # def create(self, validated_data): + # print(validated_data) + # return super().create(validated_data) diff --git a/users/views.py b/users/views.py index 85864c2..7962f66 100644 --- a/users/views.py +++ b/users/views.py @@ -35,10 +35,10 @@ def post(self, request, *args, **kwargs): return Response(serializer.data, status=status.HTTP_201_CREATED) -class CreateUserProfileAPIView(generics.CreateAPIView): - permission_classes = (IsAuthenticated, ) - model = UserProfile - serializer_class = ... +# class CreateUserProfileAPIView(generics.CreateAPIView): +# permission_classes = (IsAuthenticated, ) +# model = UserProfile +# serializer_class = ... From f35f34410d5f907b2fbff0a8b9d10bb44cad90c8 Mon Sep 17 00:00:00 2001 From: whatislove118 Date: Sat, 14 Aug 2021 19:01:30 +0300 Subject: [PATCH 5/6] create_user_profile --- questions/migrations/0001_initial.py | 40 ---------- questions/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-38.pyc | Bin 1349 -> 0 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 182 -> 0 bytes .../__pycache__/settings.cpython-38.pyc | Bin 3599 -> 3757 bytes stackoverflow_api/settings.py | 14 ++-- users/__pycache__/models.cpython-38.pyc | Bin 4869 -> 5239 bytes users/__pycache__/serializers.cpython-38.pyc | Bin 1537 -> 1918 bytes users/__pycache__/urls.cpython-38.pyc | Bin 561 -> 642 bytes users/__pycache__/views.cpython-38.pyc | Bin 1727 -> 1814 bytes users/migrations/0001_initial.py | 50 +++++++----- users/migrations/0002_auto_20210811_1219.py | 71 ------------------ users/migrations/0003_auto_20210812_1631.py | 29 ------- users/migrations/0004_alter_user_id.py | 19 ----- users/migrations/0005_auto_20210814_0546.py | 36 --------- users/migrations/0006_alter_user_id.py | 18 ----- .../__pycache__/0001_initial.cpython-38.pyc | Bin 2391 -> 2474 bytes .../0002_auto_20210811_1219.cpython-38.pyc | Bin 1391 -> 0 bytes .../0003_auto_20210812_1631.cpython-38.pyc | Bin 1188 -> 0 bytes .../0004_alter_user_id.cpython-38.pyc | Bin 668 -> 0 bytes .../0005_auto_20210814_0546.cpython-38.pyc | Bin 1206 -> 0 bytes .../0006_alter_user_id.cpython-38.pyc | Bin 654 -> 0 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 178 -> 178 bytes users/models.py | 24 ++++-- users/serializers.py | 10 ++- users/urls.py | 5 +- users/views.py | 21 ++++-- 27 files changed, 80 insertions(+), 257 deletions(-) delete mode 100644 questions/migrations/0001_initial.py delete mode 100644 questions/migrations/__init__.py delete mode 100644 questions/migrations/__pycache__/0001_initial.cpython-38.pyc delete mode 100644 questions/migrations/__pycache__/__init__.cpython-38.pyc delete mode 100644 users/migrations/0002_auto_20210811_1219.py delete mode 100644 users/migrations/0003_auto_20210812_1631.py delete mode 100644 users/migrations/0004_alter_user_id.py delete mode 100644 users/migrations/0005_auto_20210814_0546.py delete mode 100644 users/migrations/0006_alter_user_id.py delete mode 100644 users/migrations/__pycache__/0002_auto_20210811_1219.cpython-38.pyc delete mode 100644 users/migrations/__pycache__/0003_auto_20210812_1631.cpython-38.pyc delete mode 100644 users/migrations/__pycache__/0004_alter_user_id.cpython-38.pyc delete mode 100644 users/migrations/__pycache__/0005_auto_20210814_0546.cpython-38.pyc delete mode 100644 users/migrations/__pycache__/0006_alter_user_id.cpython-38.pyc diff --git a/questions/migrations/0001_initial.py b/questions/migrations/0001_initial.py deleted file mode 100644 index 27bba48..0000000 --- a/questions/migrations/0001_initial.py +++ /dev/null @@ -1,40 +0,0 @@ -# Generated by Django 3.2.6 on 2021-08-10 13:01 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Question', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=50)), - ('description', models.TextField()), - ('date_created', models.DateTimeField(auto_now_add=True)), - ('views', models.IntegerField(default=1)), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='Comment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('description', models.TextField()), - ('like', models.IntegerField(default=0)), - ('is_useful', models.BooleanField(default=False)), - ('date_created', models.DateTimeField(auto_now_add=True)), - ('question', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='questions.question')), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL)), - ], - ), - ] diff --git a/questions/migrations/__init__.py b/questions/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/questions/migrations/__pycache__/0001_initial.cpython-38.pyc b/questions/migrations/__pycache__/0001_initial.cpython-38.pyc deleted file mode 100644 index af6ceae16e9824b94b654f24fc68120d0a0785af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1349 zcmZux&2rl|5GF`Uq9{ss9OuWKP7b~4BHFn$)9G~LN_OIDZMU_2;RQnpD;gB|6N0j> zT-&SPA-T1W&{x5=C*ON%4s92t6g$&`1I+GXvESm`1<$)(*TC`X^;YnZQmL9r#z4rEsrI`+Hc@$rQ+`1V1B`$$BQO~WEU@1-pc%K` zlZXTk*m0Yg%mO#=FoGXu!J0Sr%w#RJdCXz$8-kh(?z`@L1Emhyd+6y^_AY80tj9Jg zZ4SVcDpuc?4EDlb%rft(gR zuTVUOG1sBdv4%>sD;hGU8kZcd>ZuONyap3!$7ht9!rQT1#@UmQMOR%AwW0 zC{-?{*n0~BD0`H?S%g9(q1NIlFOiMH($Tl&RhZ}D1RWXVkTOW8%fi%K8~f+u*Yy1C z;3s-~Iy(4Xc^^GENYxouR3GaOFZ7F2-nTs3$08i+%c%D7A}m(o7_Q4&?2eGiF;AdY zy`!{*2v&aXVO9W-((kZlO%{h~lqr))jgepAGj%2Z)tr0>X3^^)!WXhD)uw zqf>fvI(~h0@=Cc`4y)(*n^Am;c~;8@>YrnMqGRyrRiY$g{ zDQUj+Wf@NAxL?eKu6WMOAq zadGy@vk&IqcBi)0mLB<>Jo^i+e^%%F4mM)N!(f`Fv$`(rm4!{J64u=Bd^8T~f6idd iS>fwD>um0BUrR60rktW9 diff --git a/questions/migrations/__pycache__/__init__.cpython-38.pyc b/questions/migrations/__pycache__/__init__.cpython-38.pyc deleted file mode 100644 index 06255acb8c312fd30bfa644a3de73964058a6fbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 182 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 ZtWC6l5y=me=>Kk~m?#fuPI07Y{R7(xb6fxb diff --git a/users/__pycache__/serializers.cpython-38.pyc b/users/__pycache__/serializers.cpython-38.pyc index 14ed136ede8beb8cafb6ea0bbbedeb9345416810..41d45cb22ddf90c9de73851f43959e73e1ca1c05 100644 GIT binary patch delta 571 zcmZutyGjF55WTaHWMi`HBQe2ej1X}ZECO2CTG$04*u-L4cW)qJF=2LN5duLHNGHht zfC?7DO8fy!zhNso|3aLb2c~df&Ye4R?#!KYm-;dEOI=@JWTo$%{rRSA0HrVshlU#; zuxiZJD$GnoneYKJ?^kdx^&CmCrzT>V{EXbs5(KOZeE=3fLu$x1y4^#Cji78Qk=nxg zO@NC;i{j1e26qBKN;=5xfLm>!<4D4sC>po6S9dAvT7)*PP;vrkwnp{X2NG>H%qtFpA=1nZX!e!Xb4p|Lc*;NKwRT(mc zRaM$v4fmDT-U)HW!!%F;Gj#h`2+_+I)juKn>{05%6Ul(|d1lJEPDiBr?G{JOQ;b^# zBZv}~<#@L5Th?q_stLj=>&>sac}ZejV6#^Dc!gt~)ar0Nn(S`IFeQ5G0t^A-JL5Ky pJ{{n2&zlVyi(3?ww15J^G5K^?Lm6kv;hy>o1(GuteyKZf@C(peZ%6n1vLT!3J=fAxH%ikl{CMV~Y=9Lud7eIvdqu8M=KTV#= nL5x96MVyltGRm+C0$p7sIQcMRjEDe`DZnVeB*F|NA@DZRH%FD~e00dS{qKP{g85kaeILLql$Z-JT;);pdhCYl8sf;PCsq70l7c!)< zrLgxh1Nj`OEMPt-l+TsQio)kk&w6Zg0>GEHV;RGw_lXvgfQ n$vt@vW6LaWCJQme2=M`#0*nGo0?a@X1pfd4;6)-@ diff --git a/users/__pycache__/views.cpython-38.pyc b/users/__pycache__/views.cpython-38.pyc index 2dd523d7d2cfb30676e36de5a7100ffe5bd6caa2..d7a19b6fa7f5e1ca9cff76c97309a4fc94415727 100644 GIT binary patch literal 1814 zcmZ`(OK%%D5GMDf)%)RBnii-JX#-uPIHw$n!a@?H?m;yir3H9dY(z>~c~`q3S5|E( zC#OgMfu7o9{t~Z65B&>0b%v`zvXic`pU7{xA;q+m8d2 zV|dl?0Gx0dlY}x#acsp_Vlz8&m}BO4>?R)bk`gPKxfArs~zbCvb>{pntfvNF2F!eRF#~Uw6xA_nF zN4iuurXmj(O2{Bdxrn=#_NQVlWHeUVQ+b##6mo+&PM3rErEZ?6!6JVn=6N&@bHP7Q z?VkyirE?`#v zKNd`m;Z=tKf-uSnvxGgR%n>f2$0@ho6IS9jgz4zU3z6f_gVU3rBe5Lg_a7e=3+F$< zt9*bQ1iPm2oi)_-NS1(tEgU7{i7rX;b|F-*ols68H|IKFz&S(3Q=`cXF?tELAz4 zu4({;Rv`T~`1$l||C7x1aPhEPk^8Vz9w6L9a1p*hz}nKTX?a;i;t=5*1gz&RFv@=k z9PVYh#3)Z4TO#|3_7uotTzUv_S9@$w)LxWXg_}mx_cq?IuZXq$!*2Di|5yZt|5(8C zJ_6py@>>KjPJMz4F=8by*C5}H1kNa(d? zD$k{jr(kKY`?oEYV4)`D!+YO(Z}Q%o`Q&~tyF2A_NrUHNt?mD| zChk1>I=MMBM>M7}BQj&lvtsJe+&7~_Y{rg>sBwYgf7Y40Z;oQ$wfa-7>_`qf)5!N zT|Ki0e8@$xCo?*^+*o(E_`cxs;6-xChY;Avjpw_m9}GABK)ek23CL4Bu-m3c_JfFn z+k7avpK=t{fV?NRx+E*4rCRznX{tbfObY6o-XSIROP{~fhN?vCDyGq`0IKjw3a|+! zRL?c_n#`&-2ptx#t=GtP-v9b2D`FB;KO6I3m=LaKfm zH*5pU^ A^8f$< diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py index 7271e23..79f2a11 100644 --- a/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -1,9 +1,8 @@ -# Generated by Django 3.2.6 on 2021-08-10 13:01 +# Generated by Django 3.2.6 on 2021-08-14 15:58 -import django.contrib.auth.models -import django.contrib.auth.validators from django.db import migrations, models -import django.utils.timezone +import django.db.models.deletion +import uuid class Migration(migrations.Migration): @@ -18,28 +17,43 @@ class Migration(migrations.Migration): migrations.CreateModel( name='User', fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('password', models.CharField(max_length=128, verbose_name='password')), ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('login', models.CharField(blank=True, max_length=150)), + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('username', models.CharField(db_index=True, max_length=255, unique=True)), + ('email', models.EmailField(db_index=True, max_length=254, unique=True)), + ('is_active', models.BooleanField(default=True)), + ('is_staff', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), ], options={ - 'verbose_name': 'user', - 'verbose_name_plural': 'users', - 'abstract': False, + 'unique_together': {('username', 'email')}, }, - managers=[ - ('objects', django.contrib.auth.models.UserManager()), + ), + migrations.CreateModel( + name='UserProfile', + fields=[ + ('user', models.OneToOneField(default='', on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='users.user')), + ('logo', models.ImageField(default='/media/users/default/logo.png', upload_to='media/default//logo/')), + ('location', models.CharField(blank=True, max_length=200, null=True)), + ('about', models.TextField(blank=True, max_length=255, null=True)), + ('title', models.CharField(blank=True, max_length=100, null=True)), + ], + ), + migrations.CreateModel( + name='UserProfileContactInfo', + fields=[ + ('user_profile', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='users.userprofile')), + ('website_link', models.URLField(blank=True, null=True)), + ('github_link', models.URLField(blank=True, null=True)), + ('twitter_link', models.URLField(blank=True, null=True)), + ('website_link_active', models.BooleanField(default=False)), + ('github_link_active', models.BooleanField(default=False)), + ('twitter_link_active', models.BooleanField(default=False)), ], ), ] diff --git a/users/migrations/0002_auto_20210811_1219.py b/users/migrations/0002_auto_20210811_1219.py deleted file mode 100644 index e090aed..0000000 --- a/users/migrations/0002_auto_20210811_1219.py +++ /dev/null @@ -1,71 +0,0 @@ -# Generated by Django 3.2.6 on 2021-08-11 09:19 - -import datetime -from django.db import migrations, models -from django.utils.timezone import utc - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0001_initial'), - ] - - operations = [ - migrations.AlterModelOptions( - name='user', - options={}, - ), - migrations.AlterModelManagers( - name='user', - managers=[ - ], - ), - migrations.RemoveField( - model_name='user', - name='date_joined', - ), - migrations.RemoveField( - model_name='user', - name='first_name', - ), - migrations.RemoveField( - model_name='user', - name='last_name', - ), - migrations.RemoveField( - model_name='user', - name='login', - ), - migrations.AddField( - model_name='user', - name='created_at', - field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2021, 8, 11, 9, 19, 42, 187727, tzinfo=utc)), - preserve_default=False, - ), - migrations.AddField( - model_name='user', - name='updated_at', - field=models.DateTimeField(auto_now=True), - ), - migrations.AlterField( - model_name='user', - name='email', - field=models.EmailField(db_index=True, max_length=254, unique=True), - ), - migrations.AlterField( - model_name='user', - name='is_active', - field=models.BooleanField(default=True), - ), - migrations.AlterField( - model_name='user', - name='is_staff', - field=models.BooleanField(default=False), - ), - migrations.AlterField( - model_name='user', - name='username', - field=models.CharField(db_index=True, max_length=255, unique=True), - ), - ] diff --git a/users/migrations/0003_auto_20210812_1631.py b/users/migrations/0003_auto_20210812_1631.py deleted file mode 100644 index 34d6e95..0000000 --- a/users/migrations/0003_auto_20210812_1631.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 3.2.6 on 2021-08-12 13:31 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion -import uuid - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0002_auto_20210811_1219'), - ] - - operations = [ - migrations.AlterUniqueTogether( - name='user', - unique_together={('username', 'email')}, - ), - migrations.CreateModel( - name='UserProfile', - fields=[ - ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), - ('logo', models.ImageField(default='/media/users/default/logo.png', upload_to='media/default//logo/')), - ('location', models.CharField(blank=True, max_length=200, null=True)), - ('user', models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ], - ), - ] diff --git a/users/migrations/0004_alter_user_id.py b/users/migrations/0004_alter_user_id.py deleted file mode 100644 index 10f472e..0000000 --- a/users/migrations/0004_alter_user_id.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 3.2.6 on 2021-08-12 13:36 - -from django.db import migrations, models -import uuid - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0003_auto_20210812_1631'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='id', - field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), - ), - ] diff --git a/users/migrations/0005_auto_20210814_0546.py b/users/migrations/0005_auto_20210814_0546.py deleted file mode 100644 index 022bda2..0000000 --- a/users/migrations/0005_auto_20210814_0546.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 3.2.6 on 2021-08-14 02:46 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0004_alter_user_id'), - ] - - operations = [ - migrations.CreateModel( - name='UserProfileContactInfo', - fields=[ - ('user_profile', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='users.userprofile')), - ('website_link', models.URLField(blank=True, null=True)), - ('github_link', models.URLField(blank=True, null=True)), - ('twitter_link', models.URLField(blank=True, null=True)), - ('website_link_active', models.BooleanField(default=False)), - ('github_link_active', models.BooleanField(default=False)), - ('twitter_link_active', models.BooleanField(default=False)), - ], - ), - migrations.AddField( - model_name='userprofile', - name='about', - field=models.TextField(blank=True, max_length=255, null=True), - ), - migrations.AddField( - model_name='userprofile', - name='title', - field=models.CharField(blank=True, max_length=100, null=True), - ), - ] diff --git a/users/migrations/0006_alter_user_id.py b/users/migrations/0006_alter_user_id.py deleted file mode 100644 index 13f634f..0000000 --- a/users/migrations/0006_alter_user_id.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.2.6 on 2021-08-14 02:51 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0005_auto_20210814_0546'), - ] - - operations = [ - migrations.AlterField( - model_name='user', - name='id', - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - ] diff --git a/users/migrations/__pycache__/0001_initial.cpython-38.pyc b/users/migrations/__pycache__/0001_initial.cpython-38.pyc index f2bf720b5e164fcbc7e2d883cbb8b70761118fc7..d5630f9e7df437d2b85263ff270e1460f0769d00 100644 GIT binary patch literal 2474 zcmZWr&2!sC6qjWA+o|0oO%rHA&<}8-c2Y_yP)gIJEuA5yLlX|>pjms@@;Ym+x>_}f zPt3s8e+d5xf5YAwF6736VFs9KdAsW*Zm>qrdcXJf?fYD5XKt?Iz_0%Md31TsaemXx z?9T`09^C0IAlSh!b4G5*9eEwk)x5`Y9pC)tJNZWr&SC#22m8bw7Jkfi3fOz*H1mhB z)@gdGGNO?{lJYoJg%QVurB8ZVHv3xw<{sSXU#{a2r{iL$<6*ax!(QZee3Bm)^e&`0 zEa5!%abe>1JzNC7j9s`&xID=LQURobtGI^e@EL>D0jZMOa1Kxx?#9Fiy|c!Wi{}Ab zFnWuCoB{6KF|uTAx%m9Vg%!(&t4_HU;PlRK7}=Xs?ty6}1OZuCt6cp<^DX^43wSY(wMtD3gQE zmDSa?8zEwnh%ifm^r=W?7^4vhM`%A}B#z`j`8yy}r39tv9vArV2WTeKd?zZk7esV< zO3YeSVF=7H9?^Jgo&)pT%&B~rp?FvMamJX?gQ99Q4bvVZVX&?tk z0-?s1fb1uX_NZhB0eA@pXdJ;(GHQ(*$JT>XBAKP& zMiG-f%9vE;0bxlf$-cDScoa8%QP+-@2&NKs8Bx_l&=C>`;VwB)WpITeM#n^zv|Bn^ zhp%)-a;k*8A&oKF7iDdskj3;zlH#v@2aR|pO zfst9z_7*j{3PkzP<9vLvJ%YYLZL_jHZL_u(wURg*U$fF9{7yHcOkSsP(9dG%3LXa( z-!l%ToNf=Un!e}+MFuQ0v32J^u{|H-{T{Z=uG*?t9wC7W(Dq#q(yo`}BRJAaCo*|~I z3S5!KRKk#|8YT&WfsA{Uq{7olsBV}c+tM#fk<&7$j)-Mz_c><- z#g;4Y>^$DIkA9X>tn!-PRFwyMyseltW*aDBlSDI)iPZDCEw7;r!$9BnG OUF@^~q~Vs_Qtm%6A^e8` literal 2391 zcmZuzOOqQl5cZ76&-FgDyII0Z5CSnt#=C()LP07o5~w1n6xroq4pZ_-w&j&2N7C%Z zbE1IjUO90{xbc^C<+N9hR6%HIybp@Z)X3^qt6TcMZpl0I^UV@Gzdc*QKhBj(e>mav z6M=9GK7A7!QX&B_bp!t!`rnY3$5A&LSGtv;7_WAN2PIM_(a$9k(P&irsobrR;7O@n zIRqc2NA1uy$84amVNz&Y9ZN#FPTkn)X9I*=@abMqDp4P`8G);)QGCDI_B_EKBe(i10Ho(_9`OwRkKwbm+GPy!x(jk|~ zreD|AOn=quKO!F&`oRKNU4zJ<{8}cT&h}J$zW$=r2NcQmg9xxZOKt!=pV`L4BUZM7 zqX=ha*uAj1xpg(c+)$Nd8k#;++9U#xX)?yo5>Cay3~jUnV>V>uz74;=*N$upX3Hd1 z6dOwH+(fZ4R?}pcPHh8B8RjgfwzWr9PipG@+4=-)y)P9x`~i6PX>uGvwLoQ?97Av} z2TbI?k9@yfwv`^oV%J6@)Iwthgjhh z2+>F?)TjGY#poMqoaQnjY`_d`NDy?Z6L&6ku5=P41)s);zc^H@c7ZA-RWhbp;{nxb z4b*DUHD^7>d%z9BMk+l6{e<$o>HEm-q+M3a$1^=U4bP4n%YE0I*$N$F#t;7i+kD>l z5hg@IbX#{68QkyZH%`&BKcs-LaxfPVrC2zg5ferhykRnC0%>MwoVUD(83(ojE&&|2 zM|1j0pGT}~;FlBBqsSCV3IwBKW{h@(rktj;EMY<$AOy)if|H6GmjgIWWhQ_fTP-Hp zIlzo2Bgq6Mxff6&v_rM(fbtksii8bMu(Q>HlG#M(cpElc^ow2k?Ceo4#Q>64#^^X@ zAX^92{4ZgP zi@IDnk|1xPhJ6}`kRN_SOU_Yps&?}8PbM^FeU|>GqWX}l$2Aw{i$3z>Z`#5R)zE})FlB(bd|d75GF=7UsYf*CldY>Utd6@-eELAitupt-v~X&$<(OO-uj zci7-IoO$xz;z(u)#*?XXeFdzc!>Am-j4DwOhO5C+umbNz-@4vPunxM7VB^nl zISk_&S@)sCrIkJk<9UBMVfPDAxQT!D z6)xZbQC{YDsz^>Vn){hgob0P053`VXKX?#8_=^Xjp!4WwKZ}6e_tI#E@!s8(+9a1V z&5bOJ%0_t!LRBfTer+Zb=d$}9qi_@dDj=RGyo`XCQ6Mvt`68HyKqVGlQp6F^85VAE z2PlLPUE#O&SYVei53_SjGG7YZycRfjOkZBx41&9Be#5p zi@f(I^{~Z}c_E8wiKY6yHYF>{r;G#G4u~nQmAR7!dVv0I^>8YM0=vJ^0#=G;bgA)nO3c4fu* z#K;Sg5`EQ0$Ec|cpH6M;_;j?aUZLS`dT3+Tu)>&47{d{+l|bBQ>`Bd)^K=r3g}{2n zM2bpNm-672GD4p@n(wtuv4>mL*=1jT5_x$c?lkw0Zviw&`!2=cHeUUK%r{oYgh5fe zcWRR+TN{{s?{44X{Iw?*~Xl#Ahyx}1xNso3KA5Gk5GM!TLW*Up6;HX}LQKJp8l_N2qpAo5Ulq%<&FOJom?mM-ymvYNb=u03)#CwTiq6+ z_4nokX-AK+zU{)C7qjvN9yR@H7|)K^%GyX(oj9&vlts&T6TD@uMPIl~@z?ECeB+u{ MMecHBpY;9z0Xq$T#Q*>R diff --git a/users/migrations/__pycache__/0003_auto_20210812_1631.cpython-38.pyc b/users/migrations/__pycache__/0003_auto_20210812_1631.cpython-38.pyc deleted file mode 100644 index 5c37c9f734e97777034c24cf6a031dd407d94bb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1188 zcmY*YOK;mo5GI$TMCxHXcG{#s+eTtrX zwaM)bL9fRh-h+PXf|m|>pSvjD#$FLV!03<<`G}7<1pOWKN0{G5+1pqcAs88R7k1L! zw4d&!w_ra#;J0)xw)y^s#3Z`S53rZp$~(D!ICkMQ704>OGo4Onlr?ohXVY0YeGrB; zoP|FqTj#OP)!&?Dpd83pA~0mP?rxJOFB_nB5ktKOsfG)z{6!Y4M1Ud*e>V4R)#tEc zji{9iJgM0^riP_VGA1wS1zai*_asatSDVKwOO7&O(rm(;vg-c3&kPLpti5cPdE zc%HEs+Gdsabj@UEj$h<3FHm)EubY%2{9L(h7f4{`o*m8U>EifU5`D$)lg0dJx;Q)f zm7csfJUUi`qJ%Bi|1#tRYg+a1D$rn8!K*b+uoA^@5QYzeL#Qt5q70A(DJ<)XmX|?Q zv*iWmNda8N?-r6>&^-= Vrrd`eypJ@1m5XYGPjOAx`VU$=U8w*7 diff --git a/users/migrations/__pycache__/0004_alter_user_id.cpython-38.pyc b/users/migrations/__pycache__/0004_alter_user_id.cpython-38.pyc deleted file mode 100644 index c8bc2285de83aa4b6a82c3b9e60b4ad71ee32516..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 668 zcmYjP!EVz)5MA5r#&)SxaiD@f@FkAZ2=#!fB2`5ksE{BRUsl`9B&@TE&8|%qu5hFu z!cXuad*#G0AfYnrg4(g>X=moGXWrQJgM*BbeH$Oi9|2=OeelpY1!v@TOaKf5%{D<5 zY{DuGd>rbiie52@fPZDcF{t^MsNxX5V|o0G?yx*`*+#95>{PS0Zg0~7YJ0ixwTG5c za7J!t1jwoYSQSFB3aSWs9YY8a?$skq>J&J{e4s=8&TJ|w`i<8 znoK6gLiSxFrjuzoIVq>2e12Ry?&~g8aPdCpZUnfLz3yCspgMV_(e1ZJZKTM?G=z7!kNpO7XK~tJ2Ov-I>2vP%)Q>?`U7p+>gE%c zYyY?+3m+J)@jUUfk{J)C;$s Ib{HhlUl@S4qW}N^ diff --git a/users/migrations/__pycache__/0005_auto_20210814_0546.cpython-38.pyc b/users/migrations/__pycache__/0005_auto_20210814_0546.cpython-38.pyc deleted file mode 100644 index 9601d6f719c21d260078c428946413ab60be19ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1206 zcmZ8gOK;Oa5VqHL;yn9;mP(wFa>=7=Q4a{Uq!c01f@pimWwq%}5<43^tT#>5D_rvf z_zC{+E!v~Yc{Z?Hqpvc4IxxLgE#c#=92ZgE>! zBfDddNQc-46XA5+R~C1;`^n-i*rE5)>3E!+ST*k&eXJVM#Zl0gOa*b2=-epgAd=&A zqgz~M1bcXruSme^*xc$6Zujku18#^BxdXW{4}Mq(b73(oahH2M$MbWyN4Sr=GD=)t zm=nas|8VI)Tt-|$|H|A(>*_yfX%Y4Fe0ff=f+}C(tEgGR9BX(U%pLx4ZfY}{b<`}Q zbmLyrcRDNl5%ytI7mn^4fZgyW3CKjRHk-|D%7g+*jf4hVub(0FPR6}JKs$~UJ6Erx zUaZTh!8lW#9$u}aA?k+S3Tv(|#1X~Tf&yI{%V5Ohj1FO@3uqNE5nO>L3S&*7n*<7| z2%@1Wrz==A)NV8pLYMl18ce#WPM6g*P^LU%sn-_$C{`9+K+V>94m~yzO0O=s-m3N5 zVuU*%g1OiTbgmbG;E66R{D$^eH=d~L8=QffBdhqq>0y^tK-5!AfljOu>=K zAsr*Byp7;AMsjFM);S)ss2^*>yV_4%j-##f?fsMX{=rM_pS^#R8J1tfu>clj$lvEY z;|iy6sczZ!fXR$4#$&jBCSNSs#KbB2*=wBP6()`80N+p|;tOcCb{hwf3{^aC;JAcv zt`a()H4>bdA?jsM#8b+~K_eZM#{K(i;MDCI%YHqcfyRB{7+}VCwAJ3$D>v=qh zN$or2#`RpAkjM6Nx~n$sALO@NMk(&1UuVmxx%#{ z!igjQ;wvY90ST3H3Tnsl$TRQBkx+3=+b$>} zD*|9e2*ENaIEpIr18`LBfS?t@2zKrS#CM$V7!n$my5#NuDKs+LSTwen=6QY~)uwOd zB45n&qxrtf5B3k8@VE;#d^mUEo3oj4vz05{x`en|)%r8K@eP`* z)}mai24|e4c{xMngzvfNT4N0tv&6-6=u7ERDT%kKk str: """ return make_password(value) + def create(self, validated_data): + print(validated_data) + return User.objects.create_user(**validated_data) + # def validate(self, data): # print(data) # return data @@ -51,9 +55,9 @@ class Meta: model = UserProfile exclude = ('id', ) - # def create(self, validated_data): - # print(validated_data) - # return super().create(validated_data) + def create(self, validated_data): + print(validated_data) + return super().create(validated_data) diff --git a/users/urls.py b/users/urls.py index f3f31ee..54ac3b1 100644 --- a/users/urls.py +++ b/users/urls.py @@ -1,11 +1,12 @@ from django.urls import path, include from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView -from .views import GetUserAPIView, CreateUserAPIView +from .views import GetUserAPIView, CreateUserAPIView, CreateUserProfileAPIView urlpatterns = [ path('hello/', GetUserAPIView.as_view(), name='hello'), path('auth/', TokenObtainPairView.as_view(), name='auth'), path('refresh/', TokenRefreshView.as_view(), name='auth'), - path('register/', CreateUserAPIView.as_view(), name='reg') + path('register/', CreateUserAPIView.as_view(), name='reg'), + path('accounts/profile/', CreateUserProfileAPIView.as_view(), name='profile') ] \ No newline at end of file diff --git a/users/views.py b/users/views.py index 7962f66..7e8a76c 100644 --- a/users/views.py +++ b/users/views.py @@ -1,16 +1,13 @@ from django.contrib.auth import get_user_model -from django.shortcuts import render from rest_framework import generics, status # Create your views here. from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.response import Response from rest_framework_simplejwt.authentication import JWTAuthentication -from rest_framework_simplejwt.tokens import RefreshToken -from rest_framework_simplejwt.views import TokenObtainPairView from users.models import UserProfile -from users.serializers import CreateUserSerializer +from users.serializers import CreateUserSerializer, UserProfileSerializer class GetUserAPIView(generics.RetrieveAPIView): @@ -27,7 +24,9 @@ class CreateUserAPIView(generics.CreateAPIView): model = get_user_model() serializer_class = CreateUserSerializer + ## этого можно было и не делать, но чисто для себя я написал def post(self, request, *args, **kwargs): + print(request.user) user = request.data serializer = self.serializer_class(data=user) if serializer.is_valid(raise_exception=True): @@ -35,10 +34,16 @@ def post(self, request, *args, **kwargs): return Response(serializer.data, status=status.HTTP_201_CREATED) -# class CreateUserProfileAPIView(generics.CreateAPIView): -# permission_classes = (IsAuthenticated, ) -# model = UserProfile -# serializer_class = ... +class CreateUserProfileAPIView(generics.CreateAPIView): + permission_classes = (IsAuthenticated, ) + authentication_classes = [JWTAuthentication, ] + model = UserProfile + serializer_class = UserProfileSerializer + + # def post(self, request, *args, **kwargs): + # print(request.user) + # return Response('2') + From 2a0779538ac87b76788e1958ddac188610db495a Mon Sep 17 00:00:00 2001 From: whatislove118 Date: Fri, 20 Aug 2021 22:02:29 +0300 Subject: [PATCH 6/6] finish_user_profile --- .../__pycache__/settings.cpython-38.pyc | Bin 3757 -> 3757 bytes stackoverflow_api/settings.py | 5 +- users/__pycache__/models.cpython-38.pyc | Bin 5239 -> 6250 bytes users/__pycache__/permissions.cpython-38.pyc | Bin 0 -> 639 bytes users/__pycache__/serializers.cpython-38.pyc | Bin 1918 -> 2250 bytes users/__pycache__/urls.cpython-38.pyc | Bin 642 -> 705 bytes users/__pycache__/views.cpython-38.pyc | Bin 1814 -> 3101 bytes users/migrations/0001_initial.py | 29 ++++---- ...ename_user_profile_userprofile_contacts.py | 18 +++++ .../__pycache__/0001_initial.cpython-38.pyc | Bin 2474 -> 2637 bytes ...rofile_userprofile_contacts.cpython-38.pyc | Bin 0 -> 595 bytes .../__pycache__/__init__.cpython-38.pyc | Bin 178 -> 178 bytes users/models.py | 68 ++++++++++++------ users/permissions.py | 10 +++ users/serializers.py | 22 ++++-- users/urls.py | 7 +- users/utils.py | 11 +++ users/views.py | 62 ++++++++++++---- 18 files changed, 173 insertions(+), 59 deletions(-) create mode 100644 users/__pycache__/permissions.cpython-38.pyc create mode 100644 users/migrations/0002_rename_user_profile_userprofile_contacts.py create mode 100644 users/migrations/__pycache__/0002_rename_user_profile_userprofile_contacts.cpython-38.pyc create mode 100644 users/permissions.py create mode 100644 users/utils.py diff --git a/stackoverflow_api/__pycache__/settings.cpython-38.pyc b/stackoverflow_api/__pycache__/settings.cpython-38.pyc index c4c319ff088d5645533a985454ddea65548d7a7b..c9e5e5958acd6899870c1c17a0f45c5341a71962 100644 GIT binary patch delta 119 zcmZ20yH=Jrl$V!_0SLN&%O^hG$eYAyYTe72!Ul%6saz>cP-vH8pW=|>nBtV;oZ^z= zn&OtqoMM&Y-pdH2ZBnc^FJbg%=f1^~l2}>%k`ZX$WLC~oT#QldxtV#TC8@=m&v9;I LVPu)y$fpAUxDz5_ delta 119 zcmZ20yH=Jrl$V!_0SG>uh$lYV$eYAyYTL`0!Ul$Rsaz>cP-vgxkm8u)l;WJ?lH!`; zmg1huoMM$?-OC81ZBlGEFJbg%7mH%g&CDw;NiBZK2sBcY@fJ%;VrB8ll`!_09O7=Ggcs4SQl^Y-;ysZ3L~>#>~<~`v@Y}u)&eHL-K*ibR%Ch3xc$b7$_e9hSmuox!LPYX}Sf6veDAvG}MqwP`5`hFM*-=Dg5yzpnX|3!j)=P@`NzVIjK zvDbEeHkgTZ`&aJQf*k^fZ+1i^(P8{IyJl}q3@tvEt-8t*V@kx9luK+;S!BK%Y2ejG z6}-Nvu4Jww85Y?}Ccc#YQ*{7Vr3DJl8PS=XZUtgj{H!?=n2k<5syCugP^!9`+@@zy zM*4F-q*sSM#v@w*Ohc2oO_{be zvthQfqLTTtV%7P30MwEXk~{0aPVOWRl8@#0Hu$wG#fOdIi3vEd27{$TrDytH6?;g#mx#=AneQ^y z$@TA`g;es2>ac|zMQSXpzZHLGANI+sC}go8U*QsY1|%)cx2JzGANWxR8S`c!wnSxf z?o=NSqWZglhboB4#8G_Q(XDgElg^zn6XHO*XT)!Q?v-o}x5N_-2ePq_B>4IY46nDK+ki|m#7f0dVCdze&`lcjSQ zpg*9=lLxm1iU+T1F^dW6`^ugTD38*B-^I(t-QBCYmkqS09++Im*T6Yl7F4hx%s(Pr_NFNVhr-%Ph6*#y9zS;W_^}fw<-IRmCytOl|ASflB=wF2 zE52LW$4yN7^bkqhOw;mE6jiO18qR F{{uH-i{1bL delta 1763 zcmZ`(O>Epm6!!RM?e*GT?@xBqbkl4~)5J-L0<>yr+A3*CN~I*FYI0c+#?4IHgxz%* zdxfaBL?XSR2%-T*Z;4bPl?#UmaX{iqIe^jw7bDIP1QIv6!5c56n<}+6pWmO~oB7_% z{5Ja6fVE(nx&Y5lzZAXAo=vNSKHnU=_Ik~%m`K0^R;yMmT}dP1vVb+5yer@&k=Lb) z4Z4m~pr?pJv~{_X0gHi6u$V+&$wEvHEEZ0KCHz_u2Q_$6e699L_`c^6O&d z2=0K+6(X6JW-K{l4)Ija0z5!;fc>52R$Up>Li5EC!?;36Z{b%T() z?()u$`aLx898dW?hbQ99n_iCiZJ~7^Po*HcN;NX@|!#KLZE|_I@${u^e zgv@h5{&8O684f1^qI9Fa{8odwp$|XaBDAgeK4+0UOG57*2oLx!(GWcYpE;+iJsJDK z9?kOAM*39ETdqzolPacZW@oxlHyg>!jC1BA)xWVq7Q=wP02<|cjh^PfGago(o&?7j zjG)B6%k-3EeG&8nj|$p2jG)d2JC3elc|)nFL|W0Xf)$cn(YI2>*hV0kII$sDEbyf< zf)`HS1{`S6GqIkG_3XZ1kM$f*!3HpB57d~ad^(W;T=sK83w?KqFE&d0br+K=Sqljr z0N1o5N6L+=SAR2->(IX_*;uXm9tN^w|K39gawK{gKJ;Y{!yE^k03v!S;I` zFYOLwijSNo7sM=*|4E28vQg}NI_Dwta=A4Ew-=VMOym_6E5N@7QW7i@FfLZ~16t~U zW`Jg58LJxzI`ddgx5+lvpaV%-hAB2UIpy7tcE5h~LHW^pyWi~Y?6RM83$MnP$~@3c zrywG3PmA1XP#v+2=n*i?IhiNv?c=|3j_C{s-flX}p_h62Gw33_m%nuGF!st2^gfJ$ z-^g&Qpn_;2ctrylD4w*_L0@E3#VUJPJf28G6xG?E#bPDJMSe8mogFE&K5U^@Wll8Xo;f;@nR?6_5iY>S3u4`(lBt$zXkH)g~D diff --git a/users/__pycache__/permissions.cpython-38.pyc b/users/__pycache__/permissions.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b4b213f2608e97b186a7f021791ab774935ac321 GIT binary patch literal 639 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 diff --git a/users/migrations/__pycache__/0002_rename_user_profile_userprofile_contacts.cpython-38.pyc b/users/migrations/__pycache__/0002_rename_user_profile_userprofile_contacts.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..165254ff8016cb36d2ef22c12426bee6af2d12de GIT binary patch literal 595 zcmYjNO-~y!5VhC4>E?q9l_NLAC6{c{Qx8?ep@LHp0&&U3+GZxH6KB1(H;s_E!IdAv zU$WFwPyGu>2*xH68EZ!KX6*5MbG^6MVPqfw9+nHv*uMaFEhTV5?v5w`1FqSUk2z;& z3=$Cc3f*whITBA<-xQ7* zFQ{*)+N@<+t0Jl{-WOYt{?F3JU*)dg2sYy7R{Nm7v4VKC$lX4LTqG}PmhvQ==kz6Z l&uK+%n3vVe4B%%J7VGa4-m(K4;PbC<+xZsey0C str: """ Hash value passed by user. @@ -31,9 +32,12 @@ def validate_password(self, value: str) -> str: """ return make_password(value) - def create(self, validated_data): - print(validated_data) - return User.objects.create_user(**validated_data) + # def create(self, validated_data): + # return super().create(validated_data) + + # def create(self, validated_data): + # print(validated_data) + # return User.objects.create_user(**validated_data) # def validate(self, data): # print(data) @@ -50,10 +54,18 @@ def create(self, validated_data): # return token +class UserProfileContactInfoSerializer(serializers.ModelSerializer): + class Meta: + model = UserProfileContactInfo + fields = ['website_link', 'twitter_link', 'github_link'] + + class UserProfileSerializer(serializers.ModelSerializer): + contacts = UserProfileContactInfoSerializer(many=False, read_only=True) # так мы добавляем сериализованный обьект в другой обьект + class Meta: model = UserProfile - exclude = ('id', ) + fields = ('logo', 'location', 'about', 'title', 'contacts') def create(self, validated_data): print(validated_data) diff --git a/users/urls.py b/users/urls.py index 54ac3b1..79e03d0 100644 --- a/users/urls.py +++ b/users/urls.py @@ -1,12 +1,13 @@ from django.urls import path, include from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView -from .views import GetUserAPIView, CreateUserAPIView, CreateUserProfileAPIView +from .views import GetUserAPIView, UserCreateAPIView, UserProfileDetailAPIView, TestClass urlpatterns = [ path('hello/', GetUserAPIView.as_view(), name='hello'), path('auth/', TokenObtainPairView.as_view(), name='auth'), path('refresh/', TokenRefreshView.as_view(), name='auth'), - path('register/', CreateUserAPIView.as_view(), name='reg'), - path('accounts/profile/', CreateUserProfileAPIView.as_view(), name='profile') + path('register/', UserCreateAPIView.as_view(), name='reg'), + path('/profile/', UserProfileDetailAPIView.as_view(), name='profile'), + path('test///', TestClass.as_view()), ] \ No newline at end of file diff --git a/users/utils.py b/users/utils.py new file mode 100644 index 0000000..b444a14 --- /dev/null +++ b/users/utils.py @@ -0,0 +1,11 @@ + +from rest_framework.views import exception_handler + +def user_exception_handler(exc, context): + # Call REST framework's default exception handler first, + # to get the standard error response. + response = exception_handler(exc, context) + + if response is not None: + response.data['status_code'] = response.status_code + return response diff --git a/users/views.py b/users/views.py index 7e8a76c..db54b5c 100644 --- a/users/views.py +++ b/users/views.py @@ -1,26 +1,29 @@ from django.contrib.auth import get_user_model -from rest_framework import generics, status +from rest_framework import generics, status, permissions # Create your views here. -from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.generics import get_object_or_404 + from rest_framework.response import Response +from rest_framework.views import APIView from rest_framework_simplejwt.authentication import JWTAuthentication - from users.models import UserProfile +from users.permissions import IsResourceOwner from users.serializers import CreateUserSerializer, UserProfileSerializer +User = get_user_model() class GetUserAPIView(generics.RetrieveAPIView): - permission_classes = [IsAuthenticated, ] - authentication_classes = [JWTAuthentication, ] + permission_classes = (permissions.IsAuthenticated, ) + authentication_classes = (JWTAuthentication, ) def get(self, request, *args, **kwargs): return Response('1') ## чтобы уж совсем не быть ленивым, я напишу свою регистрацию -class CreateUserAPIView(generics.CreateAPIView): - permission_classes = (AllowAny, ) +class UserCreateAPIView(generics.CreateAPIView): + permission_classes = (permissions.AllowAny, ) model = get_user_model() serializer_class = CreateUserSerializer @@ -34,15 +37,46 @@ def post(self, request, *args, **kwargs): return Response(serializer.data, status=status.HTTP_201_CREATED) -class CreateUserProfileAPIView(generics.CreateAPIView): - permission_classes = (IsAuthenticated, ) - authentication_classes = [JWTAuthentication, ] - model = UserProfile +class TestClass(generics.RetrieveAPIView): + multiple_lookup_fields = ('username', 'email', ) + # пример как сделать поиск по нескольким лукапам + # данный метод вызывается тогда, когда достается обьект по лукапам + # тут недоделанный вариант, пока нет в этом необходимости + def get_object(self): + queryset = self.get_queryset() + filter = {} + for field in self.multiple_lookup_fields: + filter[field] = self.kwargs[field] + obj = get_object_or_404(queryset, **filter) + self.check_object_permissions(self.request, obj) + return obj + +class UserProfileDetailAPIView(generics.RetrieveUpdateAPIView): + queryset = UserProfile.objects.all() + lookup_field = 'username' + permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsResourceOwner) ## данный пермиссионс требует авторизации только в тех методах запросов, которые изменяют данные + authentication_classes = (JWTAuthentication, ) serializer_class = UserProfileSerializer + detail = {'detail': 'User with that id doesn\'t exist'} + + def get(self, request, *args, **kwargs): + data = self.get_object() + serializer = self.serializer_class(data) + return Response(serializer.data, status=status.HTTP_200_OK) + + # def patch(self, request, *args, **kwargs): + # return super().patch(request, *args, **kwargs) + + def get_object(self) -> UserProfile: + user = User.objects.get(username=self.kwargs.get(self.lookup_field)) ## вот так достаем из lookup + obj = get_object_or_404(self.get_queryset(), user=user) + self.check_object_permissions(self.request, obj) + return obj + + + + - # def post(self, request, *args, **kwargs): - # print(request.user) - # return Response('2')