From 7276bd0b2a822b98fd3c71a807577d436b398c7a Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 26 Jun 2018 22:13:39 +0800 Subject: [PATCH 1/4] =?UTF-8?q?[Update]=20=E6=9B=B4=E6=96=B0=E8=8E=B7?= =?UTF-8?q?=E5=8F=96session=20log=E7=9A=84=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E4=BB=A5=E5=90=8E=E7=BB=9F=E4=B8=80=E5=88=B0media/replay?= =?UTF-8?q?=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api.py | 89 +++++++++++++++++++++++++++++--------------- apps/users/api.py | 12 ++---- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/apps/terminal/api.py b/apps/terminal/api.py index fbbae5e22..2fde3fb60 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -258,10 +258,35 @@ class SessionReplayViewSet(viewsets.ViewSet): serializer_class = ReplaySerializer permission_classes = (IsSuperUserOrAppUser,) session = None + upload_to = 'replay' # 仅添加到本地存储中 - def gen_session_path(self): + def get_session_path(self, version=2): + """ + 获取session日志的文件路径 + :param version: 原来后缀是 .gz,为了统一新版本改为 .replay.gz + :return: + """ + suffix = '.replay.gz' + if version == 1: + suffix = '.gz' date = self.session.date_start.strftime('%Y-%m-%d') - return os.path.join(date, str(self.session.id) + '.gz') + return os.path.join(date, str(self.session.id) + suffix) + + def get_local_path(self, version=2): + session_path = self.get_session_path(version=version) + if version == 2: + local_path = os.path.join(self.upload_to, session_path) + else: + local_path = session_path + return local_path + + def save_to_storage(self, f): + local_path = self.get_local_path() + try: + name = default_storage.save(local_path, f) + return name, None + except OSError as e: + return None, e def create(self, request, *args, **kwargs): session_id = kwargs.get('pk') @@ -270,42 +295,46 @@ class SessionReplayViewSet(viewsets.ViewSet): if serializer.is_valid(): file = serializer.validated_data['file'] - file_path = self.gen_session_path() - try: - default_storage.save(file_path, file) - return Response({'url': default_storage.url(file_path)}, - status=201) - except IOError: - return Response("Save error", status=500) + name, err = self.save_to_storage(file) + if not name: + msg = "Failed save replay `{}`: {}".format(session_id, err) + logger.error(msg) + return Response({'msg': str(err)}, status=400) + url = default_storage.url(name) + return Response({'url': url}, status=201) else: - logger.error( - 'Update load data invalid: {}'.format(serializer.errors)) + msg = 'Upload data invalid: {}'.format(serializer.errors) + logger.error(msg) return Response({'msg': serializer.errors}, status=401) def retrieve(self, request, *args, **kwargs): session_id = kwargs.get('pk') self.session = get_object_or_404(Session, id=session_id) - path = self.gen_session_path() + # 新版本和老版本的文件后缀不同 + session_path = self.get_session_path() # 存在外部存储上的路径 + local_path = self.get_local_path() + local_path_v1 = self.get_local_path(version=1) - if default_storage.exists(path): - url = default_storage.url(path) - return redirect(url) - else: - configs = settings.TERMINAL_REPLAY_STORAGE - configs = [cfg for cfg in configs if cfg['TYPE'] != 'server'] - if not configs: - return HttpResponseNotFound() + # 去default storage中查找 + for _local_path in (local_path, local_path_v1, session_path): + print("Check {}".format(_local_path)) + if default_storage.exists(_local_path): + url = default_storage.url(_local_path) + return redirect(url) - date = self.session.date_start.strftime('%Y-%m-%d') - file_path = os.path.join(date, str(self.session.id) + '.replay.gz') - target_path = default_storage.base_location + '/' + path - storage = jms_storage.get_multi_object_storage(configs) - ok, err = storage.download(file_path, target_path) - if ok: - return redirect(default_storage.url(path)) - else: - logger.error("Failed download replay file: {}".format(err)) - return HttpResponseNotFound() + # 去定义的外部storage查找 + configs = settings.TERMINAL_REPLAY_STORAGE + configs = {k: v for k, v in configs.items() if v['TYPE'] != 'server'} + if not configs: + return HttpResponseNotFound() + + target_path = os.path.join(default_storage.base_location, local_path) # 保存到storage的路径 + storage = jms_storage.get_multi_object_storage(configs) + ok, err = storage.download(session_path, target_path) + if not ok: + logger.error("Failed download replay file: {}".format(err)) + return HttpResponseNotFound() + return redirect(default_storage.url(local_path)) class SessionReplayV2ViewSet(SessionReplayViewSet): diff --git a/apps/users/api.py b/apps/users/api.py index dbc5b66a8..ae4e47b60 100644 --- a/apps/users/api.py +++ b/apps/users/api.py @@ -128,16 +128,12 @@ class UserToken(APIView): return Response({'error': msg}, status=406) -class UserProfile(APIView): - permission_classes = (IsValidUser,) +class UserProfile(generics.RetrieveAPIView): + permission_classes = (IsAuthenticated,) serializer_class = UserSerializer - def get(self, request): - # return Response(request.user.to_json()) - return Response(self.serializer_class(request.user).data) - - def post(self, request): - return Response(self.serializer_class(request.user).data) + def get_object(self): + return self.request.user class UserOtpAuthApi(APIView): From 401a7f88a848f80ad0a0edadcc497701fc5f027c Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 26 Jun 2018 22:27:16 +0800 Subject: [PATCH 2/4] =?UTF-8?q?[Update]=20=E6=9B=B4=E6=96=B0=E4=BE=9D?= =?UTF-8?q?=E8=B5=96storage=E7=9A=84=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index bcba2627c..25d28f259 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -61,7 +61,7 @@ pytz==2018.3 PyYAML==3.12 redis==2.10.6 requests==2.18.4 -jms-storage==0.0.17 +jms-storage==0.0.18 s3transfer==0.1.13 simplejson==3.13.2 six==1.11.0 From eb95a0a9123a968d01874243f03d8d67a9e698f6 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 27 Jun 2018 10:34:16 +0800 Subject: [PATCH 3/4] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E6=94=B9=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E5=BD=95=E5=83=8F=E6=B2=A1=E6=9C=89=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/terminal/api.py b/apps/terminal/api.py index 2fde3fb60..f5c76a73f 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -317,7 +317,6 @@ class SessionReplayViewSet(viewsets.ViewSet): # 去default storage中查找 for _local_path in (local_path, local_path_v1, session_path): - print("Check {}".format(_local_path)) if default_storage.exists(_local_path): url = default_storage.url(_local_path) return redirect(url) @@ -329,6 +328,9 @@ class SessionReplayViewSet(viewsets.ViewSet): return HttpResponseNotFound() target_path = os.path.join(default_storage.base_location, local_path) # 保存到storage的路径 + target_dir = os.path.dirname(target_path) + if not os.path.isdir(target_dir): + os.makedirs(target_dir, exist_ok=True) storage = jms_storage.get_multi_object_storage(configs) ok, err = storage.download(session_path, target_path) if not ok: From 40022899743152448d7d271ff038e5f3b904b7d9 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 3 Jul 2018 13:23:21 +0800 Subject: [PATCH 4/4] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E4=B8=AD=E5=88=A0=E9=99=A4=E6=97=B6=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/users/templates/users/user_detail.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/users/templates/users/user_detail.html b/apps/users/templates/users/user_detail.html index 22ab4b5d4..d40251563 100644 --- a/apps/users/templates/users/user_detail.html +++ b/apps/users/templates/users/user_detail.html @@ -421,8 +421,8 @@ $(document).ready(function() { APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail}); }).on('click', '.btn-delete-user', function () { var $this = $(this); - var name = "{{ user.name }}"; - var uid = "{{ user.id }}"; + var name = "{{ user_object.name }}"; + var uid = "{{ user_object.id }}"; var the_url = '{% url "api-users:user-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid); var redirect_url = "{% url 'users:user-list' %}"; objectDelete($this, name, the_url, redirect_url);