Use otp_required permission decorator
This commit is contained in:
parent
79bff5505e
commit
4e52a4e867
7 changed files with 40 additions and 38 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
from rest_framework.permissions import BasePermission
|
from rest_framework.permissions import BasePermission, IsAuthenticated
|
||||||
|
|
||||||
|
|
||||||
class IsOwner(BasePermission):
|
class IsOwner(BasePermission):
|
||||||
|
|
@ -21,3 +21,9 @@ class IsPostOwner(BasePermission):
|
||||||
return bool(is_category_user and is_rule_user)
|
return bool(is_category_user and is_rule_user)
|
||||||
|
|
||||||
return is_rule_user
|
return is_rule_user
|
||||||
|
|
||||||
|
|
||||||
|
class TwoFactorAuthenticated(IsAuthenticated):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
is_authenticated = super().has_permission(request, view)
|
||||||
|
return is_authenticated and request.user.is_verified()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
|
from django_otp.decorators import otp_required
|
||||||
from two_factor.views import (
|
from two_factor.views import (
|
||||||
BackupTokensView,
|
BackupTokensView,
|
||||||
DisableView,
|
DisableView,
|
||||||
|
|
@ -43,42 +43,43 @@ settings_patterns = [
|
||||||
# Integrations
|
# Integrations
|
||||||
path(
|
path(
|
||||||
"integrations/reddit/callback/",
|
"integrations/reddit/callback/",
|
||||||
login_required(RedditTemplateView.as_view()),
|
otp_required(RedditTemplateView.as_view()),
|
||||||
name="reddit-template",
|
name="reddit-template",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"integrations/reddit/refresh/",
|
"integrations/reddit/refresh/",
|
||||||
login_required(RedditTokenRedirectView.as_view()),
|
otp_required(RedditTokenRedirectView.as_view()),
|
||||||
name="reddit-refresh",
|
name="reddit-refresh",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"integrations/reddit/revoke/",
|
"integrations/reddit/revoke/",
|
||||||
login_required(RedditRevokeRedirectView.as_view()),
|
otp_required(RedditRevokeRedirectView.as_view()),
|
||||||
name="reddit-revoke",
|
name="reddit-revoke",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"integrations/twitter/auth/",
|
"integrations/twitter/auth/",
|
||||||
login_required(TwitterAuthRedirectView.as_view()),
|
otp_required(TwitterAuthRedirectView.as_view()),
|
||||||
name="twitter-auth",
|
name="twitter-auth",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"integrations/twitter/callback/",
|
"integrations/twitter/callback/",
|
||||||
login_required(TwitterTemplateView.as_view()),
|
otp_required(TwitterTemplateView.as_view()),
|
||||||
name="twitter-template",
|
name="twitter-template",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"integrations/twitter/revoke/",
|
"integrations/twitter/revoke/",
|
||||||
login_required(TwitterRevokeRedirectView.as_view()),
|
otp_required(TwitterRevokeRedirectView.as_view()),
|
||||||
name="twitter-revoke",
|
name="twitter-revoke",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"integrations/", login_required(IntegrationsView.as_view()), name="integrations"
|
"integrations/", otp_required(IntegrationsView.as_view()), name="integrations"
|
||||||
),
|
),
|
||||||
# Misc
|
# Misc
|
||||||
path("favicon/", login_required(FaviconRedirectView.as_view()), name="favicon"),
|
path("favicon/", otp_required(FaviconRedirectView.as_view()), name="favicon"),
|
||||||
path("", login_required(SettingsView.as_view()), name="home"),
|
path("", otp_required(SettingsView.as_view()), name="home"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# permissions are handled through the views itself
|
||||||
two_factor = [
|
two_factor = [
|
||||||
path("accounts/setup/", SetupView.as_view(), name="setup"),
|
path("accounts/setup/", SetupView.as_view(), name="setup"),
|
||||||
path("accounts/qrcode/", QRGeneratorView.as_view(), name="qr"),
|
path("accounts/qrcode/", QRGeneratorView.as_view(), name="qr"),
|
||||||
|
|
@ -140,7 +141,7 @@ urlpatterns = [
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"password-change/",
|
"password-change/",
|
||||||
login_required(PasswordChangeView.as_view()),
|
otp_required(PasswordChangeView.as_view()),
|
||||||
name="password-change",
|
name="password-change",
|
||||||
),
|
),
|
||||||
# Settings
|
# Settings
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ REST_FRAMEWORK = {
|
||||||
"rest_framework.authentication.SessionAuthentication",
|
"rest_framework.authentication.SessionAuthentication",
|
||||||
),
|
),
|
||||||
"DEFAULT_PERMISSION_CLASSES": (
|
"DEFAULT_PERMISSION_CLASSES": (
|
||||||
"rest_framework.permissions.IsAuthenticated",
|
"newsreader.accounts.permissions.TwoFactorAuthenticated",
|
||||||
"newsreader.accounts.permissions.IsOwner",
|
"newsreader.accounts.permissions.IsOwner",
|
||||||
),
|
),
|
||||||
"DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",),
|
"DEFAULT_RENDERER_CLASSES": ("rest_framework.renderers.JSONRenderer",),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
|
from django_otp.decorators import otp_required
|
||||||
|
|
||||||
from newsreader.news.collection.endpoints import (
|
from newsreader.news.collection.endpoints import (
|
||||||
DetailRuleView,
|
DetailRuleView,
|
||||||
NestedRuleView,
|
NestedRuleView,
|
||||||
|
|
@ -29,48 +30,46 @@ endpoints = [
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# Feeds
|
# Feeds
|
||||||
path(
|
path("feeds/<int:pk>/", otp_required(FeedUpdateView.as_view()), name="feed-update"),
|
||||||
"feeds/<int:pk>/", login_required(FeedUpdateView.as_view()), name="feed-update"
|
path("feeds/create/", otp_required(FeedCreateView.as_view()), name="feed-create"),
|
||||||
),
|
|
||||||
path("feeds/create/", login_required(FeedCreateView.as_view()), name="feed-create"),
|
|
||||||
# Generic rules
|
# Generic rules
|
||||||
path("rules/", login_required(CollectionRuleListView.as_view()), name="rules"),
|
path("rules/", otp_required(CollectionRuleListView.as_view()), name="rules"),
|
||||||
path(
|
path(
|
||||||
"rules/delete/",
|
"rules/delete/",
|
||||||
login_required(CollectionRuleBulkDeleteView.as_view()),
|
otp_required(CollectionRuleBulkDeleteView.as_view()),
|
||||||
name="rules-delete",
|
name="rules-delete",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"rules/enable/",
|
"rules/enable/",
|
||||||
login_required(CollectionRuleBulkEnableView.as_view()),
|
otp_required(CollectionRuleBulkEnableView.as_view()),
|
||||||
name="rules-enable",
|
name="rules-enable",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"rules/disable/",
|
"rules/disable/",
|
||||||
login_required(CollectionRuleBulkDisableView.as_view()),
|
otp_required(CollectionRuleBulkDisableView.as_view()),
|
||||||
name="rules-disable",
|
name="rules-disable",
|
||||||
),
|
),
|
||||||
path("rules/import/", login_required(OPMLImportView.as_view()), name="import"),
|
path("rules/import/", otp_required(OPMLImportView.as_view()), name="import"),
|
||||||
# Reddit
|
# Reddit
|
||||||
path(
|
path(
|
||||||
"subreddits/create/",
|
"subreddits/create/",
|
||||||
login_required(SubRedditCreateView.as_view()),
|
otp_required(SubRedditCreateView.as_view()),
|
||||||
name="subreddit-create",
|
name="subreddit-create",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"subreddits/<int:pk>/",
|
"subreddits/<int:pk>/",
|
||||||
login_required(SubRedditUpdateView.as_view()),
|
otp_required(SubRedditUpdateView.as_view()),
|
||||||
name="subreddit-update",
|
name="subreddit-update",
|
||||||
),
|
),
|
||||||
# Twitter
|
# Twitter
|
||||||
path(
|
path(
|
||||||
"twitter/timelines/create/",
|
"twitter/timelines/create/",
|
||||||
login_required(TwitterTimelineCreateView.as_view()),
|
otp_required(TwitterTimelineCreateView.as_view()),
|
||||||
name="twitter-timeline-create",
|
name="twitter-timeline-create",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"twitter/timelines/<int:pk>/",
|
"twitter/timelines/<int:pk>/",
|
||||||
login_required(TwitterTimelineUpdateView.as_view()),
|
otp_required(TwitterTimelineUpdateView.as_view()),
|
||||||
name="twitter-timeline-update",
|
name="twitter-timeline-update",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,8 @@ from rest_framework.generics import (
|
||||||
RetrieveUpdateDestroyAPIView,
|
RetrieveUpdateDestroyAPIView,
|
||||||
get_object_or_404,
|
get_object_or_404,
|
||||||
)
|
)
|
||||||
from rest_framework.permissions import IsAuthenticated
|
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from newsreader.accounts.permissions import IsPostOwner
|
|
||||||
from newsreader.core.pagination import CursorPagination
|
from newsreader.core.pagination import CursorPagination
|
||||||
from newsreader.news.collection.serializers import RuleSerializer
|
from newsreader.news.collection.serializers import RuleSerializer
|
||||||
from newsreader.news.core.filters import ReadFilter, SavedFilter
|
from newsreader.news.core.filters import ReadFilter, SavedFilter
|
||||||
|
|
@ -21,7 +19,6 @@ from newsreader.news.core.serializers import CategorySerializer, PostSerializer
|
||||||
class ListPostView(ListAPIView):
|
class ListPostView(ListAPIView):
|
||||||
queryset = Post.objects.all()
|
queryset = Post.objects.all()
|
||||||
serializer_class = PostSerializer
|
serializer_class = PostSerializer
|
||||||
permission_classes = (IsAuthenticated, IsPostOwner)
|
|
||||||
pagination_class = CursorPagination
|
pagination_class = CursorPagination
|
||||||
filter_backends = [ReadFilter, SavedFilter]
|
filter_backends = [ReadFilter, SavedFilter]
|
||||||
|
|
||||||
|
|
@ -29,7 +26,6 @@ class ListPostView(ListAPIView):
|
||||||
class DetailPostView(RetrieveUpdateAPIView):
|
class DetailPostView(RetrieveUpdateAPIView):
|
||||||
queryset = Post.objects.all()
|
queryset = Post.objects.all()
|
||||||
serializer_class = PostSerializer
|
serializer_class = PostSerializer
|
||||||
permission_classes = (IsAuthenticated, IsPostOwner)
|
|
||||||
|
|
||||||
|
|
||||||
class ListCategoryView(ListAPIView):
|
class ListCategoryView(ListAPIView):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
|
from django_otp.decorators import otp_required
|
||||||
|
|
||||||
from newsreader.news.core.endpoints import (
|
from newsreader.news.core.endpoints import (
|
||||||
CategoryReadView,
|
CategoryReadView,
|
||||||
DetailCategoryView,
|
DetailCategoryView,
|
||||||
|
|
@ -14,20 +15,19 @@ from newsreader.news.core.views import (
|
||||||
CategoryCreateView,
|
CategoryCreateView,
|
||||||
CategoryListView,
|
CategoryListView,
|
||||||
CategoryUpdateView,
|
CategoryUpdateView,
|
||||||
NewsView,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("categories/", login_required(CategoryListView.as_view()), name="categories"),
|
path("categories/", otp_required(CategoryListView.as_view()), name="categories"),
|
||||||
path(
|
path(
|
||||||
"categories/<int:pk>/",
|
"categories/<int:pk>/",
|
||||||
login_required(CategoryUpdateView.as_view()),
|
otp_required(CategoryUpdateView.as_view()),
|
||||||
name="category-update",
|
name="category-update",
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"categories/create/",
|
"categories/create/",
|
||||||
login_required(CategoryCreateView.as_view()),
|
otp_required(CategoryCreateView.as_view()),
|
||||||
name="category-create",
|
name="category-create",
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
|
from django_otp.decorators import otp_required
|
||||||
from drf_yasg import openapi
|
from drf_yasg import openapi
|
||||||
from drf_yasg.views import get_schema_view
|
from drf_yasg.views import get_schema_view
|
||||||
from two_factor.admin import AdminSiteOTPRequired
|
from two_factor.admin import AdminSiteOTPRequired
|
||||||
|
|
@ -21,7 +21,7 @@ schema_view = get_schema_view(schema_info, patterns=api_patterns)
|
||||||
admin.site.__class__ = AdminSiteOTPRequired
|
admin.site.__class__ = AdminSiteOTPRequired
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", login_required(NewsView.as_view()), name="index"),
|
path("", otp_required(NewsView.as_view()), name="index"),
|
||||||
path("", include((news_patterns, "news"))),
|
path("", include((news_patterns, "news"))),
|
||||||
path("", include((api_patterns, "api"))),
|
path("", include((api_patterns, "api"))),
|
||||||
path("accounts/", include((login_urls, "accounts")), name="accounts"),
|
path("accounts/", include((login_urls, "accounts")), name="accounts"),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue