Multiple changes

Started switching to generics
Added tickets
This commit is contained in:
Dusty Pianalto
2019-12-01 10:30:03 -09:00
parent 27231fda7b
commit b8f751bae9
37 changed files with 1482 additions and 144 deletions
+3 -2
View File
@@ -1,9 +1,10 @@
from django.urls import path
from .views import ChannelsAPI, ChannelDetail
from .views import ChannelsAPI, ChannelDetail, AdminChannelAPI
app_name = "channels_api"
urlpatterns = [
path("", view=ChannelsAPI.as_view(), name="list"),
path("<str:id>/", view=ChannelDetail.as_view(), name='detail')
path("<str:id>/", view=ChannelDetail.as_view(), name='detail'),
path("<str:guild_id>/admin/", view=AdminChannelAPI.as_view(), name='admin')
]
+13 -4
View File
@@ -31,7 +31,7 @@ class Channel(models.Model):
self.new_patron = data.get('new_patron')
if data.get('admin'):
self.admin = data.get('admin')
self.save()
return self
@@ -61,16 +61,25 @@ class Channel(models.Model):
return create_success_response(channel, status.HTTP_201_CREATED, many=False)
@classmethod
def get_channel_by_id(cls, id):
def get_channel_by_id(cls, guild_id, channel_id):
try:
return cls.objects.get(id=id)
return cls.get_guild_channels(guild_id).get(id=channel_id)
except ObjectDoesNotExist:
return None
@classmethod
def get_guild_channels(cls, guild):
if isinstance(guild, Guild):
return cls.objects.filter(guild=guild)
elif isinstance(guild, (str, int)):
return cls.objects.filter(guild__id=guild)
@classmethod
def get_admin_channel(cls, guild_id):
try:
return cls.get_guild_channels(guild_id).get(admin=True)
except ObjectDoesNotExist:
return None
def __str__(self):
return str(id)
+40 -12
View File
@@ -16,25 +16,53 @@ from .utils import create_success_response
class ChannelsAPI(PaginatedAPIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
guilds = Channel.objects.all()
page = self.paginate_queryset(guilds)
def get(self, request, guild_id, format=None):
channels = Channel.get_guild_channels(guild_id)
page = self.paginate_queryset(channels)
if page is not None:
return create_success_response(page, status.HTTP_200_OK, many=True)
return create_success_response(guilds, status.HTTP_200_OK, many=True)
return create_success_response(channels, status.HTTP_200_OK, many=True)
def post(self, request, format=None):
data = dict(request.data)
return Channel.add_new_channel(data)
class AdminChannelAPI(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, guild_id, format=None):
channel = Channel.get_admin_channel(guild_id)
if channel:
return create_success_response(channel, status=status.HTTP_200_OK)
return create_error_response('There is no admin channel configured for that guild',
status=status.HTTP_404_NOT_FOUND)
def put(self, request, guild_id, format=None):
data = dict(request.data)
channel = Channel.get_channel_by_id(guild_id, data['channel'])
if channel:
channel = channel.update_channel({'admin': True})
return create_success_response(channel, status=status.HTTP_202_ACCEPTED)
return create_error_response("That channel does not exist",
status=status.HTTP_404_NOT_FOUND)
def delete(self, request, guild_id, format=None):
channel = Channel.get_admin_channel(guild_id)
if channel:
channel = channel.update_channel({'admin': False})
return create_success_response(channel, status=status.HTTP_202_ACCEPTED)
return create_error_response("There is no admin channel configured",
status=status.HTTP_404_NOT_FOUND)
class ChannelDetail(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, id, format=None):
def get(self, request, guild_id, channel_id, format=None):
try:
guild = Channel.objects.get(id=id)
guild = Channel.get_channel_by_id(guild_id, channel_id)
except ObjectDoesNotExist:
return create_error_response("Channel Does not Exist",
status=status.HTTP_404_NOT_FOUND)
@@ -42,8 +70,8 @@ class ChannelDetail(APIView):
return create_success_response(guild,
status=status.HTTP_200_OK)
def put(self, request, id, format=None):
channel = Channel.get_channel_by_id(id)
def put(self, request, guild_id, channel_id, format=None):
channel = Channel.get_channel_by_id(guild_id, channel_id)
if channel:
data = dict(request.data)
@@ -54,14 +82,14 @@ class ChannelDetail(APIView):
return create_error_response('Channel Does Not Exist',
status=status.HTTP_404_NOT_FOUND)
def delete(self, request, id, format=None):
guild = Channel.get_guild_by_id(id)
def delete(self, request, guild_id, channel_id, format=None):
channel = Channel.get_channel_by_id(guild_id, channel_id)
if guild:
if channel:
# data = dict(request.data)
# TODO Add a check to verify user is allowed to delete...
# Possibly in object permissions...
guild.delete()
channel.delete()
return create_success_response(guild,
status=status.HTTP_200_OK)
else:
+1 -1
View File
@@ -24,7 +24,7 @@ DEBUG = env.bool("DJANGO_DEBUG", False)
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# though not all of them may be available with every OS.
# In Windows, this must be set to your system time zone.
TIME_ZONE = "America/Anchorage"
TIME_ZONE = "UTC"
# https://docs.djangoproject.com/en/dev/ref/settings/#language-code
LANGUAGE_CODE = "en-us"
# https://docs.djangoproject.com/en/dev/ref/settings/#site-id
+1
View File
@@ -20,6 +20,7 @@ urlpatterns = [
path("api/guilds/", include("geeksbot_v2.guilds.api_urls", namespace="guilds_api")),
path("api/channels/", include("geeksbot_v2.channels.api_urls", namespace="channels_api")),
path("api/messages/", include("geeksbot_v2.dmessages.api_urls", namespace="messages_api")),
path("api/rcon/", include("geeksbot_v2.rcon.api_urls", namespace="rcon_api")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if settings.DEBUG:
+12 -6
View File
@@ -2,14 +2,20 @@ from django.urls import path
from .views import MessageDetailAPI, MessagesAPI
from .views import RequestDetailAPI, RequestsAPI
from .views import CommentDetailAPI, CommentsAPI
from .views import CommentDetailAPI, CommentsAPI, CommentsCountAPI
from .views import WaitForMessageAPI
from .views import UserRequestsAPI
app_name = "channels_api"
app_name = "messages_api"
urlpatterns = [
path("", view=MessagesAPI.as_view(), name="message_list"),
path("<str:id>/", view=MessageDetailAPI.as_view(), name='message_detail'),
path("requests/", view=RequestsAPI.as_view(), name="requests_list"),
path("requests/<str:id>/", view=RequestDetailAPI.as_view(), name='request_detail'),
path("requests/<str:request_id>/comments/", view=CommentsAPI.as_view(), name="comments_list"),
path("requests/<str:request_id>/comments/<str:comment_id>/", view=CommentDetailAPI.as_view(), name='comment_detail'),
path("<str:guild_id>/requests/", view=RequestsAPI.as_view(), name="requests_list"),
path("<str:guild_id>/requests/<str:request_id>/", view=RequestDetailAPI.as_view(), name='request_detail'),
path("<str:guild_id>/requests/<str:request_id>/comments/", view=CommentsAPI.as_view(), name="comments_list"),
path("<str:guild_id>/requests/<str:request_id>/comments/count/", view=CommentsCountAPI.as_view(), name="comments_count"),
path("<str:guild_id>/requests/<str:request_id>/comments/<str:comment_id>/", view=CommentDetailAPI.as_view(), name='comment_detail'),
path("<str:guild_id>/requests/user/<str:author_id>/", view=UserRequestsAPI.as_view(), name='user_requests_list'),
path("<str:id>/wait/", view=WaitForMessageAPI.as_view(), name='wait_for_message'),
path("<str:id>/wait/<int:timeout>/", view=WaitForMessageAPI.as_view(), name='wait_for_message_timeout'),
]
+21 -15
View File
@@ -57,7 +57,7 @@ class Message(models.Model):
if not isinstance(guild, Guild):
return create_error_response("Guild Does Not Exist",
status=status.HTTP_404_NOT_FOUND)
channel = Channel.get_channel_by_id(channel_id)
channel = Channel.get_channel_by_id(guild_id, channel_id)
if not isinstance(channel, Channel):
return create_error_response("Channel Does Not Exist",
status=status.HTTP_404_NOT_FOUND)
@@ -89,7 +89,7 @@ class Message(models.Model):
if data.get('tagged_channels'):
tagged_channels = data.get('tagged_channels')
for channel_id in tagged_channels:
channel = Channel.get_channel_by_id(channel_id)
channel = Channel.get_channel_by_id(guild_id, channel_id)
if channel:
message.tagged_channels.add(channel)
@@ -179,8 +179,9 @@ class AdminRequest(models.Model):
def update_request(self, data):
completed = data.get('completed', False)
completed_by_id = data.get('completed_by')
completed_message = data.get('message')
completed_message = data.get('message', '')
if not self.completed and completed:
self.completed = completed
self.completed_at = datetime.utcnow()
self.completed_message = completed_message
user = User.get_user_by_id(completed_by_id)
@@ -192,8 +193,7 @@ class AdminRequest(models.Model):
return create_request_success_response(self, status.HTTP_202_ACCEPTED)
@classmethod
def add_new_request(cls, data):
guild_id = data.get('guild')
def add_new_request(cls, guild_id, data):
author_id = data.get('author')
message_id = data.get('message')
channel_id = data.get('channel')
@@ -205,7 +205,7 @@ class AdminRequest(models.Model):
if not isinstance(guild, Guild):
return create_error_response('Guild Does Not Exist',
status=status.HTTP_404_NOT_FOUND)
author = User.get_author_by_id(author_id)
author = User.get_user_by_id(author_id)
if not isinstance(author, User):
return create_error_response('Author Does Not Exist',
status=status.HTTP_404_NOT_FOUND)
@@ -213,11 +213,13 @@ class AdminRequest(models.Model):
if not isinstance(message, Message):
return create_error_response('Message Does Not Exist',
status=status.HTTP_404_NOT_FOUND)
channel = Channel.get_channel_by_id(channel_id)
channel = Channel.get_channel_by_id(guild_id, channel_id)
if not isinstance(channel, Channel):
return create_error_response('Channel Does Not Exist',
status=status.HTTP_404_NOT_FOUND)
print('test')
request = cls(
guild=guild,
author=author,
@@ -233,15 +235,19 @@ class AdminRequest(models.Model):
return cls.objects.filter(guild__id=guild_id).filter(completed=False)
@classmethod
def get_request_by_id(cls, id):
def get_open_request_by_id(cls, guild_id, request_id):
try:
return cls.objects.get(id=id)
return cls.get_open_requests_by_guild(guild_id).get(id=request_id)
except ObjectDoesNotExist:
return None
def __str__(self):
return f"{self.guild.id} | {self.requested_at} | By {self.author.id}"
@classmethod
def get_open_requests_by_guild_author(cls, guild_id, author_id):
return cls.get_open_requests_by_guild(guild_id).filter(author__id=author_id)
class AdminComment(models.Model):
request = models.ForeignKey(AdminRequest, on_delete=models.CASCADE)
@@ -250,13 +256,13 @@ class AdminComment(models.Model):
updated_at = models.DateTimeField(auto_now_add=True, blank=True)
@classmethod
def add_new_comment(cls, data, request_id):
def add_new_comment(cls, data, guild_id, request_id):
author_id = data.get('author')
content = data.get('content')
if not (request_id and author_id and content):
return create_error_response('Request, Author, and Content are required fields',
status=status.HTTP_400_BAD_REQUEST)
request = AdminRequest.get_request_by_id(request_id)
request = AdminRequest.get_open_request_by_id(guild_id, request_id)
if not isinstance(request, AdminRequest):
return create_error_response("Admin Request Does Not Exist",
status=status.HTTP_404_NOT_FOUND)
@@ -274,12 +280,12 @@ class AdminComment(models.Model):
return create_comment_success_response(comment, status.HTTP_201_CREATED, many=False)
@classmethod
def get_comment_by_id(cls, id):
def get_comment_by_id(cls, comment_id):
try:
return cls.objects.get(id=id)
return cls.objects.get(id=comment_id)
except ObjectDoesNotExist:
return None
@classmethod
def get_comments_by_request(cls, request):
return cls.objects.filter(request=request)
return cls.objects.filter(request=request).order_by('updated_at')
+68 -12
View File
@@ -1,3 +1,6 @@
from time import sleep
from datetime import datetime
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
@@ -59,27 +62,57 @@ class MessageDetailAPI(APIView):
status=status.HTTP_404_NOT_FOUND)
class WaitForMessageAPI(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, id, timeout: int = 3, format=None):
message = Message.get_message_by_id(id)
try_count = 0
while not message:
sleep(0.1)
try_count += 1
if try_count > timeout * 10:
return create_error_response("Timeout reached before message is available.",
statu=status.HTTP_404_NOT_FOUND)
message = Message.get_message_by_id(id)
return create_success_response(message, status=status.HTTP_200_OK)
class RequestsAPI(PaginatedAPIView):
permission_classes = [IsAuthenticated]
def get(self, request, guild, format=None):
requests = AdminRequest.get_open_requests_by_guild(guild)
def get(self, request, guild_id, format=None):
requests = AdminRequest.get_open_requests_by_guild(guild_id)
page = self.paginate_queryset(requests)
if page is not None:
return create_request_success_response(page, status.HTTP_200_OK, many=True)
if requests:
return create_request_success_response(requests, status.HTTP_200_OK, many=True)
return create_error_response("No requests found")
return create_request_success_response(requests, status.HTTP_200_OK, many=True)
def post(self, request, format=None):
def post(self, request, guild_id, format=None):
data = dict(request.data)
return AdminRequest.add_new_request(data)
return AdminRequest.add_new_request(guild_id, data)
class UserRequestsAPI(PaginatedAPIView):
permission_classes = [IsAuthenticated]
def get(self, request, guild_id, author_id, format=None):
requests = AdminRequest.get_open_requests_by_guild_author(guild_id, author_id)
page = self.paginate_queryset(requests)
if page is not None:
return create_request_success_response(page, status.HTTP_200_OK, many=True)
if requests:
return create_request_success_response(requests, status.HTTP_200_OK, many=True)
return create_error_response("No requests found")
class RequestDetailAPI(APIView):
permission_classes = [IsAuthenticated]
def get(self, req, id, format=None):
req = AdminRequest.get_request_by_id(id)
def get(self, req, guild_id, request_id, format=None):
req = AdminRequest.get_open_request_by_id(guild_id, request_id)
if req:
comments = AdminComment.get_comments_by_request(req)
if comments:
@@ -92,21 +125,44 @@ class RequestDetailAPI(APIView):
return create_error_response("That Request Does Not Exist",
status=status.HTTP_404_NOT_FOUND)
def put(self, request, id, format=None):
req = AdminRequest.get_request_by_id(id)
def put(self, request, guild_id, request_id, format=None):
req = AdminRequest.get_open_request_by_id(guild_id, request_id)
if req:
data = dict(request.data)
return req.update_request(data)
return create_error_response("That Request Does Not Exist",
status=status.HTTP_404_NOT_FOUND)
def delete(self, request, guild_id, request_id, format=None):
data = dict(request.data)
request = AdminRequest.get_open_request_by_id(guild_id, request_id)
data['completed'] = True
data['completed_at'] = datetime.utcnow()
return request.update_request(data)
class CommentsAPI(PaginatedAPIView):
permissions_classes = [IsAuthenticated]
def post(self, request, request_id, format=None):
def get(self, request, guild_id, request_id, format=None):
comments = AdminComment.get_comments_by_request(request_id)
if comments:
return create_comment_success_response(comments, status=status.HTTP_200_OK, many=True)
return create_error_response("No Comments found")
def post(self, request, guild_id, request_id, format=None):
data = dict(request.data)
return AdminComment.add_new_comment(data, request_id)
return AdminComment.add_new_comment(data, guild_id, request_id)
class CommentsCountAPI(PaginatedAPIView):
permissions_classes = [IsAuthenticated]
def get(self, request, guild_id, request_id, format=None):
comments = AdminComment.get_comments_by_request(request_id)
if comments:
return Response(len(comments), status=status.HTTP_200_OK)
return Response(0, status.HTTP_200_OK)
class CommentDetailAPI(APIView):
+2
View File
@@ -2,11 +2,13 @@ from django.urls import path
from .views import GuildsAPI, GuildDetail
from .views import RolesAPI, RoleDetailAPI
from .views import AdminRolesAPI
app_name = "guilds_api"
urlpatterns = [
path("", view=GuildsAPI.as_view(), name="list"),
path("<str:id>/", view=GuildDetail.as_view(), name='detail'),
path("<str:guild_id>/roles/", view=RolesAPI.as_view(), name="list"),
path("<str:guild_id>/roles/admin/", view=AdminRolesAPI.as_view(), name='admin'),
path("<str:guild_id>/roles/<str:id>/", view=RoleDetailAPI.as_view(), name='detail'),
]
+10 -3
View File
@@ -73,7 +73,7 @@ class Role(models.Model):
self.role_type = data.get('role_type')
self.save()
return create_role_success_response(self, status=status.HTTP_202_ACCEPTED, many=False)
return self
@classmethod
def add_new_role(cls, guild_id, data):
@@ -112,9 +112,9 @@ class Role(models.Model):
return create_role_success_response(role, status.HTTP_201_CREATED, many=False)
@classmethod
def get_role_by_id(cls, id):
def get_role_by_id(cls, guild_id, role_id):
try:
return cls.objects.get(id=id)
return cls.get_guild_roles(guild_id).get(id=role_id)
except ObjectDoesNotExist:
return None
@@ -122,5 +122,12 @@ class Role(models.Model):
def get_guild_roles(cls, guild):
return cls.objects.filter(guild__id=guild)
@classmethod
def get_admin_roles(cls, guild_id):
try:
return cls.get_guild_roles(guild_id).filter(role_type__gte=90)
except ObjectDoesNotExist:
return None
def __str__(self):
return f"{self.guild.id} | {self.id}"
+21 -1
View File
@@ -87,6 +87,26 @@ class RolesAPI(PaginatedAPIView):
return Role.add_new_role(guild_id, data)
class AdminRolesAPI(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, guild_id, format=None):
roles = Role.get_admin_roles(guild_id)
if roles:
return create_role_success_response(roles, status=status.HTTP_200_OK, many=True)
return create_error_response('There are no admin roles configured',
status=status.HTTP_404_NOT_FOUND)
def put(self, request, guild_id, format=None):
data = dict(request.data)
role = Role.get_role_by_id(guild_id, data['role'])
if role:
role = role.update_role({'role_type': 100})
return create_role_success_response(role, status=status.HTTP_202_ACCEPTED)
return create_error_response("That role does not exist",
status=status.HTTP_404_NOT_FOUND)
class RoleDetailAPI(APIView):
permission_classes = [IsAuthenticated]
@@ -101,7 +121,7 @@ class RoleDetailAPI(APIView):
status=status.HTTP_200_OK)
def put(self, request, guild_id, id, format=None):
role = Role.get_role_by_id(id)
role = Role.get_role_by_id(guild_id, id)
if role:
data = dict(request.data)
+77
View File
@@ -0,0 +1,77 @@
import discord
import gspread
from oauth2client.service_account import ServiceAccountCredentials
class Patron:
def __init__(self, *, discord_name: str=None, steam_id: int=None, patreon_tier: str=None, patron_of: str=None,
discord_discrim: int=None, discord_id: int=None, patreon_name: str=None, steam_name: str=None):
self.discord_name = discord_name
self.discord_discrim = discord_discrim
self.steam_id = steam_id
self.discord_id = discord_id
self.patreon_tier = patreon_tier
self.patron_of = patron_of
self.patreon_name = patreon_name
self.steam_name = steam_name
@classmethod
async def from_id(cls, bot, steam_id: int, *, discord_id: int=None):
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_dict(bot.google_secret, scope)
gc = gspread.authorize(credentials)
sh = gc.open_by_key(bot.bot_secrets['sheet'])
ws = sh.worksheet('Current Whitelist')
try:
cell = ws.find(f'{steam_id}')
except gspread.CellNotFound:
return -1
else:
steam_name = None
if discord_id:
user_ref = bot.fs_db.document(f'users/{discord_id}')
user_info = (await bot.loop.run_in_executor(bot.tpe, user_ref.get)).to_dict()
if user_info:
steam_name = user_info.get('steam_name')
row = ws.row_values(cell.row)
return cls(patreon_name=row[1],
discord_name=row[2],
steam_id=row[5],
patreon_tier=row[4].split(' (')[1].strip(')') if len(row[4].split(' (')) > 1 else row[4],
patron_of=row[3].split(' (')[0],
discord_id=discord_id,
steam_name=steam_name)
@classmethod
async def from_name(cls, bot, discord_name: discord.Member, *, discord_id: int=None):
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_dict(bot.google_secret, scope)
gc = gspread.authorize(credentials)
sh = gc.open_by_key(bot.bot_secrets['sheet'])
ws = sh.worksheet('Current Whitelist')
try:
cell = ws.find(f'{discord_name.name if isinstance(discord_name, discord.Member) else discord_name}')
except gspread.CellNotFound:
try:
cell = ws.find(f'{discord_name.nick if isinstance(discord_name, discord.Member) else discord_name}')
except gspread.CellNotFound:
return -1
steam_name = None
discord_id = discord_name.id if isinstance(discord_name, discord.Member) else discord_id
if discord_id:
user_ref = bot.fs_db.document(f'users/{discord_id}')
user_info = (await bot.loop.run_in_executor(bot.tpe, user_ref.get)).to_dict()
if user_info:
steam_name = user_info.get('steam_name')
row = ws.row_values(cell.row)
return cls(patreon_name=row[1],
discord_name=row[2],
discord_id=discord_id,
steam_id=row[5],
patreon_tier=row[4].split(' (')[1].strip(')') if len(row[4].split(' (')) > 1 else row[4],
patron_of=row[3].split(' (')[0],
steam_name=steam_name)
+10
View File
@@ -0,0 +1,10 @@
from django.urls import path
from .views import RCONServersAPI, RCONServerDetailAPI, ListPlayers
app_name = "rcon_api"
urlpatterns = [
path("<str:guild_id>/", view=RCONServersAPI.as_view(), name='guild_servers'),
path("<str:guild_id>/<str:name>/", view=RCONServerDetailAPI.as_view(), name="server_detail"),
path("<str:guild_id>/<str:name>/listplayers", view=ListPlayers.as_view(), name='listplayers'),
]
+1 -1
View File
@@ -120,7 +120,7 @@ class RconServer(models.Model):
@classmethod
def get_guild_servers(cls, guild_id):
guild = Guild.get_guild_by_id(guild_id)
if not isinstance(guild, guild):
if not isinstance(guild, Guild):
return None
return cls.objects.filter(guild=guild)
+118
View File
@@ -0,0 +1,118 @@
from . import rcon
import asyncio
from typing import Union
import logging
arcon_log = logging.getLogger('arcon_lib')
class ARKServer(rcon.RCONConnection):
def __init__(self, *args, monitor_chat: bool=False, server_chat_channel: int=None,
server_messages_channel: int=None, **kwargs):
self.monitor_chat = monitor_chat
self.server_chat_channel = server_chat_channel
self.server_messages_channel = server_messages_channel
super().__init__(*args, **kwargs)
async def run_command(self, command: str, multi_packet: bool=False, reconnect_counter: int=0) \
-> Union[rcon.RCONPacket, str]:
arcon_log.debug(f'Command requested: {command}')
if self.authenticated:
packet = rcon.RCONPacket(next(self.packet_id), rcon.SERVERDATA_EXECCOMMAND, command)
with await self.lock:
try:
arcon_log.debug(f'Sending packet {packet.packet_id}')
await self.send_packet(packet)
arcon_log.debug(f'Packet Sent.')
except ConnectionResetError:
arcon_log.info(f'Connection to {self.host}:{self.port} lost, Reconnecting...')
self.lock.release()
await self._reconnect_and_resend(packet)
await self.lock.acquire()
finally:
arcon_log.debug(f'Waiting for response to packet {packet.packet_id}')
try:
response = await self.read(packet, multi_packet=multi_packet)
except asyncio.TimeoutError as e:
if reconnect_counter > 5:
return 'Reached max reconnects. Closing connection.'
arcon_log.warning(f'No response received: {e}\nAttempting to reconnect #{reconnect_counter}')
self.lock.release()
await self._reconnect()
await self.lock.acquire()
response = await self.run_command(command=command, multi_packet=multi_packet,
reconnect_counter=reconnect_counter + 1)
arcon_log.debug(f'Response Received:\n{response.packet_type}:{response.packet_id}:{response.body}')
response.body = response.body.strip('\x00\x00').strip()
return response
else:
return 'Server is not Authenticated. Please let the Admin know of this issue.'
async def getchat(self) -> str:
response = await self.run_command(command='getchat', multi_packet=True)
return response.body if isinstance(response, rcon.RCONPacket) else response
async def saveworld(self) -> str:
response = await self.run_command(command='saveworld')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def serverchat(self, message: str) -> str:
response = await self.run_command(command=f'serverchat {message}')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def broadcast(self, message: str) -> str:
response = await self.run_command(command=f'broadcast {message}')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def listplayers(self) -> str:
response = await self.run_command(command=f'listplayers')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def whitelist(self, steam_id: str) -> str:
response = await self.run_command(command=f'AllowPlayerToJoinNoCheck {steam_id}')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def ban_player(self, steam_id: int) -> str:
response = await self.run_command(command=f'BanPlayer {steam_id}')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def unban_player(self, steam_id: int) -> str:
response = await self.run_command(command=f'UnbanPlayer {steam_id}')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def kick_player(self, steam_id: int) -> str:
response = await self.run_command(command=f'KickPlayer {steam_id}')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def stop_server(self) -> int:
saved = await self.saveworld()
if saved == 'World Saved':
await self.serverchat(saved)
await asyncio.sleep(10)
response = await self.run_command(command='DoExit')
if response.body == 'Exiting...':
return 0
else:
return 2
else:
return 1
async def get_logs(self):
response = await self.run_command(command=f'GetGameLog', multi_packet=True)
return response.body if isinstance(response, rcon.RCONPacket) else response
async def server_chat_to_steam_id(self, steam_id: int, message: str) -> str:
response = await self.run_command(command=f'ServerChatTo {steam_id} {message}')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def server_chat_to_player_name(self, player_name: str, message: str) -> str:
response = await self.run_command(command=f'ServerChatToPlayer "{player_name}" {message}')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def set_time_of_day(self, hour: int, minute: int=00, seconds: int=00) -> str:
response = await self.run_command(command=f'SetTimeOfDay {hour}:{minute}:{seconds}')
return response.body if isinstance(response, rcon.RCONPacket) else response
async def destroy_wild_dinos(self):
response = await self.run_command(command='DestroyWildDinos')
return response.body if isinstance(response, rcon.RCONPacket) else response
+183
View File
@@ -0,0 +1,183 @@
import asyncio
import logging
import itertools
import struct
# Packet types
SERVERDATA_AUTH = 3
SERVERDATA_AUTH_RESPONSE = 2
SERVERDATA_EXECCOMMAND = 2
SERVERDATA_RESPONSE_VALUE = 0
__all__ = ['RCONPacket', 'RCONConnection']
rcon_log = logging.getLogger('rcon_lib')
class RCONPacket:
def __init__(self, packet_id: int=0, packet_type: int=-1, body: str=''):
self.packet_id = packet_id
self.packet_type = packet_type
self.body = body
def __str__(self):
"""Return the body of the packet"""
return self.body
def size(self):
"""Return the size of the packet"""
return len(self.body) + 10
def pack(self):
"""Return the packed packet"""
return struct.pack(f'<3i{len(self.body) + 2}s',
self.size(),
self.packet_id,
self.packet_type,
bytearray(self.body, 'utf-8'))
class RCONConnection:
"""Connection to an RCON server"""
def __init__(self, host: str, port: int, password: str='', single_packet: bool=False, loop=None):
"""Create a New RCON Connection
Parameters:
host (str): The hostname or IP address of the server to connect to
port (int): The port to connect to on the server
password (str): The password to authenticate with the server
single_packet (bool): True for servers who don't give 0 length SERVERDATA_RESPONSE_VALUE requests
"""
self.host = host
self.port = port
self.password = password
self.single_packet = single_packet
self.packet_id = itertools.count(1)
self.loop = loop or asyncio.get_event_loop()
self.reader = None
self.writer = None
self.lock = asyncio.Lock()
self.authenticated = False
async def connect(self):
"""Returns -1 if connection times out
Returns 1 if connection and auth are successful
Returns 0 if auth fails"""
try:
rcon_log.debug(f'Connecting to {self.host}:{self.port}...')
self.reader, self.writer = await asyncio.open_connection(self.host, self.port, loop=self.loop)
except TimeoutError as e:
rcon_log.error(f'Timeout error: {e}')
return -1
else:
rcon_log.debug('Connected. Attempting to Authenticate...')
auth_packet = RCONPacket(next(self.packet_id), SERVERDATA_AUTH, self.password)
with await self.lock:
await self.send_packet(auth_packet)
response = await self.read()
if response.packet_type == SERVERDATA_AUTH_RESPONSE and response.packet_id != -1:
rcon_log.debug(f'Authorized {response.packet_type}:{response.packet_id}:{response.body}')
self.authenticated = True
return 1
else:
rcon_log.debug(f'Not Authorized {response.packet_type}:{response.packet_id}:{response.body}')
self.authenticated = False
return 0
async def _reconnect(self):
self.writer = None
self.reader = None
connected = await self.connect()
rcon_log.info(f'Connection completed with a return of {connected}')
if connected != -1:
rcon_log.info('Connected')
else:
rcon_log.warning('Connection Failed')
return connected
async def _reconnect_and_resend(self, packet):
connected = await self._reconnect()
if connected != -1:
await asyncio.sleep(0.1)
rcon_log.info(f'Re-sending packet {packet.packet_id}')
await self.send_packet(packet)
rcon_log.info(f'Packet Sent.')
return connected
else:
return connected
async def keep_alive(self):
while True:
await asyncio.sleep(60)
ka_packet = RCONPacket(next(self.packet_id), SERVERDATA_EXECCOMMAND, '')
try:
with await self.lock:
await asyncio.wait_for(self.send_packet(ka_packet), 10, loop=self.loop)
await asyncio.wait_for(self.read(ka_packet), 10, loop=self.loop)
except asyncio.TimeoutError:
self.reader = None
self.writer = None
await self.connect()
async def send_packet(self, packet):
if packet.size() > 4096:
rcon_log.error('Packet Size is larger than 4096 bytes. Cannot send packet.')
raise RuntimeWarning('Packet Size is larger than 4096 bytes. Cannot send packet.')
if self.writer is None:
await self.connect()
rcon_log.debug(f'Sending Packet {packet.packet_id}: {packet.pack() if packet.packet_type is not SERVERDATA_AUTH else "Censored for Password Security."}')
self.writer.write(packet.pack())
await self.writer.drain()
rcon_log.debug(f'Packet {packet.packet_id} Sent.')
async def read(self, request: RCONPacket=None, multi_packet=False) -> RCONPacket:
rcon_log.debug(f'Waiting to receive response to packet {request.packet_id if request else None}')
response = RCONPacket()
try:
if request:
while response.packet_id != request.packet_id and response.packet_id < request.packet_id:
if multi_packet:
if request is None:
rcon_log.warning('A request packet is required to receive a multi packet response')
raise ValueError('A request packet is required to receive a multi packet response')
await asyncio.sleep(.01)
response = await self._receive_multi_packet()
rcon_log.debug(f'Received Multi-Packet response to packet {request.packet_id}:\n'
f'{response.packet_type}:{response.packet_id}:{response.body}')
else:
response = await self.receive_packet()
rcon_log.debug(f'Received Single-Packet response to packet {request.packet_id}:\n'
f'{response.packet_type}:{response.packet_id}:{response.body}')
else:
response = await self.receive_packet()
rcon_log.debug(f'Received Single-Packet response:\n'
f'{response.packet_type}:{response.packet_id}:{response.body}')
except struct.error as e:
rcon_log.error(f'Struct Error: {e}')
response = RCONPacket(body='Error receiving data from the server. Attempting to reconnect. '
'Please try again in a little bit.')
self.lock.release()
await self._reconnect()
await self.lock.acquire()
except AttributeError as e:
rcon_log.error(f'Attribute Error: {e}')
response = RCONPacket(body='Error receiving data from the server. Attempting to reconnect. '
'Please try again in a little bit.')
self.lock.release()
await self._reconnect()
await self.lock.acquire()
return response
async def receive_packet(self):
header = await self.reader.read(struct.calcsize('<3i'))
(packet_size, packet_id, packet_type) = struct.unpack('<3i', header)
body = await self.reader.read(packet_size - 8)
return RCONPacket(packet_id, packet_type, body.decode('ascii'))
async def _receive_multi_packet(self):
header = await self.reader.read(struct.calcsize('<3i'))
(packet_size, packet_id, packet_type) = struct.unpack('<3i', header)
body = await self.reader.readuntil(separator=b'\x00\x00')
return RCONPacket(packet_id, packet_type, body.decode('ascii'))
+6 -1
View File
@@ -11,4 +11,9 @@ def create_success_response(rcon_data, status, many: bool = False):
from .serializers import RconServerSerializer
return Response(RconServerSerializer(rcon_data, many=many).data,
status=status)
status=status)
def create_rcon_response(message, status):
msg_list = message.split('\n')
return Response(msg_list, status=status)
+76 -1
View File
@@ -1,3 +1,78 @@
from django.shortcuts import render
import asyncio
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from .rcon_lib import arcon
from .models import RconServer
from .utils import create_error_response, create_success_response, create_rcon_response
from geeksbot_v2.utils.api_utils import PaginatedAPIView
from .serializers import RconServerSerializer
# Create your views here.
# API Views
class RCONServersAPI(PaginatedAPIView):
permission_classes = [IsAuthenticated]
def get(self, request, guild_id, format=None):
servers = RconServer.get_guild_servers(guild_id)
page = self.paginate_queryset(servers)
if page:
return create_success_response(page, status.HTTP_200_OK, many=True)
return create_success_response(servers, status.HTTP_200_OK, many=True)
def post(self, request, guild_id, format=None):
data = dict(request.data)
data['guild'] = guild_id
return RconServer.add_new_server(data)
class RCONServerDetailAPI(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, guild_id, name, format=None):
server = RconServer.get_server(guild_id, name)
if server:
return create_success_response(server, status.HTTP_200_OK, many=False)
else:
return create_error_response("RCON Server Does Not Exist",
status=status.HTTP_404_NOT_FOUND)
def put(self, request, guild_id, name, format=None):
data = dict(request.data)
server = RconServer.get_server(guild_id, name)
if server:
return server.update_server(data)
else:
return create_error_response('RCON Server Does Not Exist',
status=status.HTTP_404_NOT_FOUND)
class ListPlayers(PaginatedAPIView):
permission_classes = [IsAuthenticated]
def get(self, request, guild_id, name, format=None):
server: RconServer = RconServer.get_server(guild_id, name)
if server:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop = asyncio.get_event_loop()
ark = arcon.ARKServer(host=server.ip, port=server.port, password=server.password, loop=loop)
connected = loop.run_until_complete(ark.connect())
if connected == 1:
resp = loop.run_until_complete(ark.listplayers())
if resp == 'No Players Connected':
return create_rcon_response(resp, status=status.HTTP_204_NO_CONTENT)
else:
return create_rcon_response(resp, status=status.HTTP_200_OK)
else:
return create_error_response('Connection failure',
status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return create_error_response('RCON Server Does Not Exist',
status=status.HTTP_404_NOT_FOUND)
@@ -0,0 +1,74 @@
from src.shared_libs.guid import Guid
from src.shared_libs.TicTacToe.player import Player
class Board:
def __init__(self):
self.id = Guid()
self.board = [[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']]
self.history = []
self.winner = False
self.draw = False
self.play_count = 0
self.remaining_moves = [1, 2, 3, 4, 5, 6, 7, 8, 9]
self.winning_states = [[(0, 0), (0, 1), (0, 2)],
[(0, 0), (1, 1), (2, 2)],
[(1, 0), (1, 1), (1, 2)],
[(2, 0), (2, 1), (2, 2)],
[(0, 0), (1, 0), (2, 0)],
[(0, 1), (1, 1), (2, 1)],
[(0, 2), (1, 2), (2, 2)],
[(2, 0), (1, 1), (0, 2)]]
def __repr__(self):
return f'<TicTacToe Board id="{self.id}">'
def __str__(self):
return '┌───┬───┬───┐\n' \
'{0[0][0]}{0[0][1]}{0[0][2]}\n' \
'├───┼───┼───┤\n' \
'{0[1][0]}{0[1][1]}{0[1][2]}\n' \
'├───┼───┼───┤\n' \
'{0[2][0]}{0[2][1]}{0[2][2]}\n' \
'└───┴───┴───┘\n'.format(self.board)
def make_play(self, player: Player, position: int):
assert 1 <= position <= 9
assert isinstance(player, Player)
move = ((position - 1) // 3, (position - 1) % 3)
if not self.board[move[0]][move[1]] == ' ':
raise Warning("That cell is already taken. Please try again.")
self.history.append(self.board)
self.board[move[0]][move[1]] = player
self.play_count += 1
self.winner = self.check_winner()
self.draw = self.check_draw()
self.remaining_moves.remove(position)
def check_winner(self):
for state in self.winning_states:
if (self.board[state[0][0]][state[0][1]] ==
self.board[state[1][0]][state[1][1]] ==
self.board[state[2][0]][state[2][1]]) and \
self.board[state[0][0]][state[0][1]] != ' ':
return self.board[state[0][0]][state[0][1]]
return False
def check_draw(self):
for row in self.board:
for cell in row:
if cell == ' ':
return False
else:
return True
def clear(self):
self.board = [[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']]
self.history = []
self.winner = False
self.play_count = 0
+195
View File
@@ -0,0 +1,195 @@
from src.shared_libs.guid import Guid
import random
from copy import deepcopy
__all__ = ['Player', 'AIPlayer']
class Player:
def __init__(self, token: str, *, name: str=None, id: str=None, discord_id: int=None):
if len(token) != 1:
raise Warning('Token must be exactly one character long.')
self.token = token
self.name = name or f'Player {self.token}'
self.id = id or Guid()
self.starting_player = False
self.discord_id = discord_id
def __repr__(self):
return f'<TicTacToe Player name="{self.name}" id="{self.id}">'
def __str__(self):
return self.token
def __eq__(self, other):
if isinstance(other, Player) and other.id == self.id:
return True
elif isinstance(other, str):
return self.token == other
class AIPlayer(Player):
def __init__(self, token: str=None, name: str=None, human: Player=None, *, id: str=None):
token = token or '🇽'
if human:
if human.token == token and human.token != '🇴':
token = '🇴'
elif human.token == '🇴':
token = '🇽'
super().__init__(token, name=name or f'Robot {token}', id=id)
self._corner_moves = [1, 3, 7, 9]
self._side_moves = [2, 4, 6, 8]
self._center_move = 5
self.remaining_corners = deepcopy(self._corner_moves)
self.remaining_sides = deepcopy(self._side_moves)
def make_selection(self, board, last_play: int=None) -> int:
if last_play in self.remaining_corners:
self.remaining_corners.remove(last_play)
elif last_play in self.remaining_sides:
self.remaining_sides.remove(last_play)
winning_move = self.check_winning_move(board)
if winning_move:
move = winning_move
else:
blocking_move = self.check_blocking_move(board)
if blocking_move:
move = blocking_move
else:
trap_move = self.attempt_trap(board)
if trap_move:
move = trap_move
else:
starting_move = self.starting_strategy(board)
if self.starting_player and starting_move:
move = starting_move
else:
if board.board[1][1] == ' ':
move = 5
else:
if self.check_corner_trap(board):
move = random.choice(self.remaining_sides)
else:
if self.remaining_corners:
move = random.choice(self.remaining_corners)
else:
move = random.choice(self.remaining_sides)
if move in self.remaining_corners:
self.remaining_corners.remove(move)
elif move in self.remaining_sides:
self.remaining_sides.remove(move)
print(move)
return move
def starting_strategy(self, board):
move = False
if board.play_count == 0:
move = random.choice(self.remaining_corners)
self.remaining_corners.remove(move)
elif board.play_count == 2:
if (board.board[0][0] == self and ' ' != board.board[2][2] != self) \
or (board.board[2][2] == self and ' ' != board.board[0][0] != self) \
or (board.board[2][0] == self and ' ' != board.board[0][2] != self) \
or (board.board[0][2] == self and ' ' != board.board[2][0] != self):
move = random.choice(self.remaining_corners)
else:
if board.board[0][0] == self:
move = 9
elif board.board[2][2] == self:
move = 1
elif board.board[0][2] == self:
move = 7
elif board.board[2][0] == self:
move = 3
self.remaining_corners.remove(move)
elif board.play_count == 4 and self.remaining_corners:
move = random.choice(self.remaining_corners)
self.remaining_corners.remove(move)
return move
def check_corner_trap(self, board):
if ' ' != board.board[0][0] == board.board[2][2] != self:
return True
elif ' ' != board.board[0][2] == board.board[2][0] != self:
return True
return False
def check_blocking_move(self, board):
for position in board.winning_states:
if ' ' != board.board[position[0][0]][position[0][1]] == \
board.board[position[1][0]][position[1][1]] != self \
and board.board[position[2][0]][position[2][1]] == ' ':
return ((position[2][0] * 3) + position[2][1]) + 1
elif ' ' != board.board[position[0][0]][position[0][1]] == \
board.board[position[2][0]][position[2][1]] != self \
and board.board[position[1][0]][position[1][1]] == ' ':
return ((position[1][0] * 3) + position[1][1]) + 1
elif ' ' != board.board[position[2][0]][position[2][1]] == \
board.board[position[1][0]][position[1][1]] != self \
and board.board[position[0][0]][position[0][1]] == ' ':
return ((position[0][0] * 3) + position[0][1]) + 1
return False
def check_winning_move(self, board):
for position in board.winning_states:
if board.board[position[0][0]][position[0][1]] == board.board[position[1][0]][position[1][1]] == self \
and board.board[position[2][0]][position[2][1]] == ' ':
return ((position[2][0] * 3) + position[2][1]) + 1
elif board.board[position[0][0]][position[0][1]] == board.board[position[2][0]][position[2][1]] == self \
and board.board[position[1][0]][position[1][1]] == ' ':
return ((position[1][0] * 3) + position[1][1]) + 1
elif board.board[position[2][0]][position[2][1]] == board.board[position[1][0]][position[1][1]] == self \
and board.board[position[0][0]][position[0][1]] == ' ':
return ((position[0][0] * 3) + position[0][1]) + 1
return False
def attempt_trap(self, board):
if board.board[1][1] == self:
if board.board[0][0] == self and \
board.board[0][1] == ' ' and \
board.board[0][2] == ' ' and \
board.board[2][0] == ' ':
return 3
elif board.board[0][0] == self and \
board.board[1][0] == ' ' and \
board.board[0][2] == ' ' and \
board.board[2][0] == ' ':
return 7
elif board.board[0][2] == self and \
board.board[0][1] == ' ' and \
board.board[0][0] == ' ' and \
board.board[2][2] == ' ':
return 1
elif board.board[0][2] == self and \
board.board[1][2] == ' ' and \
board.board[0][0] == ' ' and \
board.board[2][2] == ' ':
return 9
elif board.board[2][0] == self and \
board.board[0][0] == ' ' and \
board.board[0][1] == ' ' and \
board.board[2][2] == ' ':
return 1
elif board.board[2][0] == self and \
board.board[2][1] == ' ' and \
board.board[2][2] == ' ' and \
board.board[0][0] == ' ':
return 9
elif board.board[2][2] == self and \
board.board[2][1] == ' ' and \
board.board[2][0] == ' ' and \
board.board[0][2] == ' ':
return 7
elif board.board[2][2] == self and \
board.board[1][2] == ' ' and \
board.board[0][2] == ' ' and \
board.board[2][0] == ' ':
return 3
return False
def reset_game(self):
self.remaining_sides = deepcopy(self._side_moves)
self.remaining_corners = deepcopy(self._corner_moves)
self.starting_player = False
View File
+3 -1
View File
@@ -1,9 +1,11 @@
from django.urls import path
from geeksbot_v2.users.views import UsersAPI, UserDetail
from geeksbot_v2.users.views import UsersAPI, UserDetail, UserLogList, UserLogDetail
app_name = "users_api"
urlpatterns = [
path("", view=UsersAPI.as_view(), name="list"),
path("<str:id>/", view=UserDetail.as_view(), name="detail"),
path("<str:id>/logs/", view=UserLogList.as_view(), name="log_list"),
path("<str:id>/logs/<str:log>", view=UserLogDetail.as_view(), name="log_detail"),
]
+29 -3
View File
@@ -4,7 +4,7 @@ from geeksbot_v2.users.models import User
from geeksbot_v2.users.models import UserLog
class UserSerializer(serializers.ModelSerializer):
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = [
@@ -21,11 +21,37 @@ class UserSerializer(serializers.ModelSerializer):
'avatar',
'bot',
'banned',
'logging_enabled'
'logging_enabled',
'is_staff',
'is_superuser',
'url'
]
extra_kwargs = {
'url': {
'view_name': 'users_api:detail',
'lookup_field': 'id'
},
'guilds': {
'view_name': 'guilds_api:detail',
'lookup_field': 'id'
}
}
class UserLogSerializer(serializers.ModelSerializer):
class Meta:
model = UserLog
fields = "__all__"
fields = [
'user',
'time',
'action',
'description',
'url'
]
extra_fields = {
'url': {
'view_name': 'users_api:log_detail',
'lookup_field': 'id',
'lookup_url_kwarg': 'log'
}
}
+74 -53
View File
@@ -4,6 +4,7 @@ from django.views.generic import DetailView, RedirectView, UpdateView
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from rest_framework.views import APIView
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
from rest_framework import status
@@ -11,6 +12,10 @@ from rest_framework import status
from .models import UserLog
from geeksbot_v2.utils.api_utils import PaginatedAPIView
from .models import User
from .serializers import UserSerializer
from .serializers import UserLogSerializer
from geeksbot_v2.utils.permissions import CustomDjangoModelPermissions
from geeksbot_v2.utils.permissions import CustomDjangoObjectPermissions
from .utils import create_error_response
from .utils import create_success_response
from .utils import create_log_success_response
@@ -66,73 +71,89 @@ user_redirect_view = UserRedirectView.as_view()
# API Views
class UsersAPI(PaginatedAPIView):
class UsersAPI(generics.ListCreateAPIView):
permission_classes = [IsAuthenticated]
serializer_class = UserSerializer
def get(self, request, guild=None, format=None):
if guild:
users = User.objects.filter(guilds__id=guild)
else:
users = User.objects.all()
page = self.paginate_queryset(users)
if page is not None:
return create_success_response(page, status.HTTP_200_OK, many=True)
def get_queryset(self):
return User.objects.filter(guilds__id=self.request.data.get('guild'))
return create_success_response(users, status.HTTP_200_OK, many=True)
def post(self, request, format=None):
data = dict(request.data)
return User.add_new_user(data)
# def get(self, request, guild=None, format=None):
# if guild:
# users = User.objects.filter(guilds__id=guild)
# else:
# users = User.objects.all()
# page = self.paginate_queryset(users)
# if page is not None:
# return create_success_response(page, status.HTTP_200_OK, many=True)
#
# return create_success_response(users, status.HTTP_200_OK, many=True)
#
# def post(self, request, format=None):
# data = dict(request.data)
# return User.add_new_user(data)
class UserDetail(APIView):
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [IsAuthenticated]
serializer_class = UserSerializer
lookup_field = 'id'
def get(self, request, id, format=None):
user = User.get_user_by_id(id)
if not isinstance(user, User):
return create_error_response("User Does not Exist",
status=status.HTTP_404_NOT_FOUND)
return create_success_response(user,
status=status.HTTP_200_OK)
def get_queryset(self):
return User.objects.all()
def put(self, request, id, format=None):
user = User.get_user_by_id(id)
if isinstance(user, User):
data = dict(request.data)
return user.update_user(data)
else:
return create_error_response("User Does Not Exist",
status=status.HTTP_404_NOT_FOUND)
# def get(self, request, id, format=None):
# user = User.get_user_by_id(id)
# if not isinstance(user, User):
# return create_error_response("User Does not Exist",
# status=status.HTTP_404_NOT_FOUND)
# return create_success_response(user,
# status=status.HTTP_200_OK)
#
# def put(self, request, id, format=None):
# user = User.get_user_by_id(id)
# if isinstance(user, User):
# data = dict(request.data)
# return user.update_user(data)
# else:
# return create_error_response("User Does Not Exist",
# status=status.HTTP_404_NOT_FOUND)
class UserLogList(PaginatedAPIView):
class UserLogList(generics.ListCreateAPIView):
permission_classes = [IsAuthenticated]
serializer_class = UserLogSerializer
def get(self, request, user, action=None, format=None):
if action:
user_logs = UserLog.get_logs_by_user_action(user, action)
else:
user_logs = UserLog.get_logs_by_user(user)
def get_queryset(self):
return UserLog.objects.all()
page = self.paginate_queryset(user_logs)
if page is not None:
return create_log_success_response(page, status.HTTP_200_OK, many=True)
return create_log_success_response(user_logs, status.HTTP_200_OK, many=True)
def post(self, request, user, format=None):
data = dict(request.data)
return UserLog.add_new_log(user, data)
# def get(self, request, user, action=None, format=None):
# if action:
# user_logs = UserLog.get_logs_by_user_action(user, action)
# else:
# user_logs = UserLog.get_logs_by_user(user)
#
# page = self.paginate_queryset(user_logs)
# if page is not None:
# return create_log_success_response(page, status.HTTP_200_OK, many=True)
#
# return create_log_success_response(user_logs, status.HTTP_200_OK, many=True)
#
# def post(self, request, user, format=None):
# data = dict(request.data)
# return UserLog.add_new_log(user, data)
class UserLogDetail(APIView):
class UserLogDetail(generics.RetrieveUpdateAPIView):
permission_classes = [IsAuthenticated]
serializer_class = UserLogSerializer
lookup_url_kwarg = 'log'
lookup_field = 'id'
def get(self, request, id, format=None):
user_log = UserLog.get_log_by_id(id)
if isinstance(user_log, UserLog):
return create_log_success_response(user_log, status.HTTP_200_OK, many=False)
else:
return create_error_response("Log Does Not Exist",
status=status.HTTP_404_NOT_FOUND)
# def get(self, request, id, format=None):
# user_log = UserLog.get_log_by_id(id)
# if isinstance(user_log, UserLog):
# return create_log_success_response(user_log, status.HTTP_200_OK, many=False)
# else:
# return create_error_response("Log Does Not Exist",
# status=status.HTTP_404_NOT_FOUND)
+27
View File
@@ -0,0 +1,27 @@
from rest_framework.permissions import DjangoModelPermissions, DjangoObjectPermissions
class CustomDjangoModelPermissions(DjangoModelPermissions):
# Overriding to require view permissions
perms_map = {
'GET': ['%(app_label)s.view_%(model_name)s'],
'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
'HEAD': ['%(app_label)s.view_%(model_name)s'],
'POST': ['%(app_label)s.add_%(model_name)s'],
'PUT': ['%(app_label)s.change_%(model_name)s'],
'PATCH': ['%(app_label)s.change_%(model_name)s'],
'DELETE': ['%(app_label)s.delete_%(model_name)s'],
}
class CustomDjangoObjectPermissions(DjangoObjectPermissions):
# Overriding to require view permissions
perms_map = {
'GET': ['%(app_label)s.view_%(model_name)s'],
'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
'HEAD': ['%(app_label)s.view_%(model_name)s'],
'POST': ['%(app_label)s.add_%(model_name)s'],
'PUT': ['%(app_label)s.change_%(model_name)s'],
'PATCH': ['%(app_label)s.change_%(model_name)s'],
'DELETE': ['%(app_label)s.delete_%(model_name)s'],
}