diff --git a/media/css/seahub.css b/media/css/seahub.css index d82359b462..3c6079aaf7 100644 --- a/media/css/seahub.css +++ b/media/css/seahub.css @@ -4332,6 +4332,28 @@ img.thumbnail { .date-custom-form .submit { margin-left:5px; } +.traffic-chart { + margin:0 0 20px; +} +.traffic-tab-nav { + margin:10px 0 16px; +} +.traffic-tab-nav .tab { + display:inline-block; + margin-right:.7em; +} +.traffic-tab-nav .a { + color:#8a948f; + font-weight:normal; + padding:.3em 0; + border-bottom:2px solid transparent; +} +.traffic-tab-nav .tab-cur .a, +.traffic-tab-nav .tab .a:hover { + color:#eb8205; + text-decoration:none; + border-bottom-color:#eb8205; +} /* system info */ .license-file-upload { diff --git a/seahub/api2/endpoints/admin/org_stats.py b/seahub/api2/endpoints/admin/org_stats.py new file mode 100644 index 0000000000..e4746e1180 --- /dev/null +++ b/seahub/api2/endpoints/admin/org_stats.py @@ -0,0 +1,43 @@ +# Copyright (c) 2012-2016 Seafile Ltd. +from rest_framework.authentication import SessionAuthentication +from rest_framework.permissions import IsAdminUser +from rest_framework.response import Response +from rest_framework.views import APIView + +from seahub.api2.authentication import TokenAuthentication +from seahub.api2.throttling import UserRateThrottle +from seahub.api2.endpoints.admin.statistics import ( + check_parameter, get_init_data, get_time_offset +) +from seahub.utils import get_org_traffic_by_day +from seahub.utils.timeutils import datetime_to_isoformat_timestr + + +class AdminOrgStatsTraffic(APIView): + authentication_classes = (TokenAuthentication, SessionAuthentication) + throttle_classes = (UserRateThrottle,) + permission_classes = (IsAdminUser,) + + @check_parameter + def get(self, request, start_time, end_time, *args, **kwargs): + org_id = kwargs['org_id'] + + op_type_list = ['web-file-upload', 'web-file-download', + 'sync-file-download', 'sync-file-upload', + 'link-file-upload', 'link-file-download'] + init_count = [0] * 6 + init_data = get_init_data(start_time, end_time, + dict(zip(op_type_list, init_count))) + + for e in get_org_traffic_by_day(org_id, start_time, end_time, + get_time_offset()): + dt, op_type, count = e + init_data[dt].update({op_type: count}) + + res_data = [] + for k, v in init_data.items(): + res = {'datetime': datetime_to_isoformat_timestr(k)} + res.update(v) + res_data.append(res) + + return Response(sorted(res_data, key=lambda x: x['datetime'])) diff --git a/seahub/api2/endpoints/admin/share_links.py b/seahub/api2/endpoints/admin/share_links.py index 9117038082..b4c10a7f9c 100644 --- a/seahub/api2/endpoints/admin/share_links.py +++ b/seahub/api2/endpoints/admin/share_links.py @@ -218,7 +218,7 @@ class AdminShareLinkDownload(APIView): try: # `username` parameter only used for encrypted repo download_token = seafile_api.get_fileserver_access_token(repo_id, - obj_id, 'download', sharelink.username, use_onetime=False) + obj_id, 'download-link', sharelink.username, use_onetime=False) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' @@ -261,7 +261,7 @@ class AdminShareLinkDownload(APIView): try: download_token = seafile_api.get_fileserver_access_token(repo_id, - real_obj_id, 'download', sharelink.username, use_onetime=False) + real_obj_id, 'download-link', sharelink.username, use_onetime=False) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' @@ -305,7 +305,7 @@ class AdminShareLinkDownload(APIView): try: zip_token = seafile_api.get_fileserver_access_token(repo_id, - json.dumps(fake_obj_id), 'download-dir', + json.dumps(fake_obj_id), 'download-dir-link', sharelink.username, use_onetime=False) except Exception as e: logger.error(e) @@ -315,9 +315,6 @@ class AdminShareLinkDownload(APIView): try: # used for file audit send_file_access_msg(request, repo, real_path, 'share-link') - # used for traffic - seaserv.send_message('seahub.stats', 'dir-download\t%s\t%s\t%s\t%s' % - (repo_id, sharelink.username, real_obj_id, dir_size)) except Exception as e: logger.error(e) diff --git a/seahub/api2/endpoints/admin/statistics.py b/seahub/api2/endpoints/admin/statistics.py index 486d31bc52..cfe5e894d5 100644 --- a/seahub/api2/endpoints/admin/statistics.py +++ b/seahub/api2/endpoints/admin/statistics.py @@ -11,7 +11,7 @@ from django.utils import timezone from seahub.utils import get_file_ops_stats_by_day, \ get_total_storage_stats_by_day, get_user_activity_stats_by_day, \ - is_pro_version, EVENTS_ENABLED + is_pro_version, EVENTS_ENABLED, get_system_traffic_by_day from seahub.utils.timeutils import datetime_to_isoformat_timestr from seahub.api2.authentication import TokenAuthentication @@ -44,7 +44,7 @@ def check_parameter(func): error_msg = "End time %s invalid" % end_time return api_error(status.HTTP_400_BAD_REQUEST, error_msg) - return func(view, request, start_time, end_time) + return func(view, request, start_time, end_time, *args, **kwargs) return _decorated @@ -129,7 +129,35 @@ class ActiveUsersView(APIView): return Response(sorted(res_data, key=lambda x: x['datetime'])) -def get_init_data(start_time, end_time): +class SystemTrafficView(APIView): + authentication_classes = (TokenAuthentication, SessionAuthentication) + throttle_classes = (UserRateThrottle,) + permission_classes = (IsAdminUser,) + + @check_parameter + def get(self, request, start_time, end_time): + op_type_list = ['web-file-upload', 'web-file-download', + 'sync-file-download', 'sync-file-upload', + 'link-file-upload', 'link-file-download'] + init_count = [0] * 6 + init_data = get_init_data(start_time, end_time, + dict(zip(op_type_list, init_count))) + + for e in get_system_traffic_by_day(start_time, end_time, + get_time_offset()): + dt, op_type, count = e + init_data[dt].update({op_type: count}) + + res_data = [] + for k, v in init_data.items(): + res = {'datetime': datetime_to_isoformat_timestr(k)} + res.update(v) + res_data.append(res) + + return Response(sorted(res_data, key=lambda x: x['datetime'])) + + +def get_init_data(start_time, end_time, init_data=0): res = {} start_time = start_time.replace(hour=0).replace(minute=0).replace(second=0) end_time = end_time.replace(hour=0).replace(minute=0).replace(second=0) @@ -138,7 +166,10 @@ def get_init_data(start_time, end_time): for offset in range(date_length): offset = offset * 24 dt = start_time + datetime.timedelta(hours=offset) - res[dt] = 0 + if isinstance(init_data, dict): + res[dt] = init_data.copy() + else: + res[dt] = init_data return res def get_time_offset(): diff --git a/seahub/api2/endpoints/admin/upload_links.py b/seahub/api2/endpoints/admin/upload_links.py index 4eb2b2bef4..55b5f470fa 100644 --- a/seahub/api2/endpoints/admin/upload_links.py +++ b/seahub/api2/endpoints/admin/upload_links.py @@ -119,7 +119,7 @@ class AdminUploadLinkUpload(APIView): return api_error(status.HTTP_404_NOT_FOUND, error_msg) upload_token = seafile_api.get_fileserver_access_token(repo_id, - obj_id, 'upload', uploadlink.username, use_onetime=False) + obj_id, 'upload-link', uploadlink.username, use_onetime=False) if not upload_token: error_msg = 'Internal Server Error' diff --git a/seahub/api2/endpoints/share_link_zip_task.py b/seahub/api2/endpoints/share_link_zip_task.py index 7204dd3623..8b570a7d52 100644 --- a/seahub/api2/endpoints/share_link_zip_task.py +++ b/seahub/api2/endpoints/share_link_zip_task.py @@ -100,12 +100,6 @@ class ShareLinkZipTaskView(APIView): error_msg = _('Unable to download directory "%s": size is too large.') % dir_name return api_error(status.HTTP_400_BAD_REQUEST, error_msg) - try: - seaserv.send_message('seahub.stats', 'dir-download\t%s\t%s\t%s\t%s' % - (repo_id, fileshare.username, dir_id, dir_size)) - except Exception as e: - logger.error(e) - is_windows = 0 if is_windows_operating_system(request): is_windows = 1 @@ -116,11 +110,11 @@ class ShareLinkZipTaskView(APIView): 'is_windows': is_windows } - username = request.user.username try: zip_token = seafile_api.get_fileserver_access_token( - repo_id, json.dumps(fake_obj_id), 'download-dir', username, - use_onetime=settings.FILESERVER_TOKEN_ONCE_ONLY) + repo_id, json.dumps(fake_obj_id), 'download-dir-link', + fileshare.username, use_onetime=settings.FILESERVER_TOKEN_ONCE_ONLY + ) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' diff --git a/seahub/api2/endpoints/upload_links.py b/seahub/api2/endpoints/upload_links.py index 53c8ddead9..03777cc832 100644 --- a/seahub/api2/endpoints/upload_links.py +++ b/seahub/api2/endpoints/upload_links.py @@ -263,7 +263,7 @@ class UploadLinkUpload(APIView): return api_error(status.HTTP_403_FORBIDDEN, error_msg) token = seafile_api.get_fileserver_access_token(repo_id, - dir_id, 'upload', uls.username, use_onetime=False) + dir_id, 'upload-link', uls.username, use_onetime=False) if not token: error_msg = 'Internal Server Error' diff --git a/seahub/templates/sysadmin/snippets/sys_org_info_nav.html b/seahub/templates/sysadmin/snippets/sys_org_info_nav.html new file mode 100644 index 0000000000..7510d1afc1 --- /dev/null +++ b/seahub/templates/sysadmin/snippets/sys_org_info_nav.html @@ -0,0 +1,8 @@ +{% load i18n %} + diff --git a/seahub/templates/sysadmin/sys_org_info_group.html b/seahub/templates/sysadmin/sys_org_info_group.html index 769a073052..5806bdb996 100644 --- a/seahub/templates/sysadmin/sys_org_info_group.html +++ b/seahub/templates/sysadmin/sys_org_info_group.html @@ -4,12 +4,9 @@ {% block right_panel %}
- + {% with cur_tab='group' %} + {% include 'sysadmin/snippets/sys_org_info_nav.html' %} + {% endwith %}
{% if groups %} diff --git a/seahub/templates/sysadmin/sys_org_info_library.html b/seahub/templates/sysadmin/sys_org_info_library.html index 462d00f331..14383e5cae 100644 --- a/seahub/templates/sysadmin/sys_org_info_library.html +++ b/seahub/templates/sysadmin/sys_org_info_library.html @@ -1,15 +1,11 @@ {% extends "sysadmin/sys_org_info_base.html" %} {% load i18n seahub_tags %} - {% block right_panel %}
- + {% with cur_tab='library' %} + {% include 'sysadmin/snippets/sys_org_info_nav.html' %} + {% endwith %}
{% if org_repos %} diff --git a/seahub/templates/sysadmin/sys_org_info_setting.html b/seahub/templates/sysadmin/sys_org_info_setting.html index 83880a6433..d596b68c1c 100644 --- a/seahub/templates/sysadmin/sys_org_info_setting.html +++ b/seahub/templates/sysadmin/sys_org_info_setting.html @@ -4,12 +4,9 @@ {% block right_panel %}
- + {% with cur_tab='setting' %} + {% include 'sysadmin/snippets/sys_org_info_nav.html' %} + {% endwith %}
diff --git a/seahub/templates/sysadmin/sys_org_info_traffic.html b/seahub/templates/sysadmin/sys_org_info_traffic.html new file mode 100644 index 0000000000..4b16c7f525 --- /dev/null +++ b/seahub/templates/sysadmin/sys_org_info_traffic.html @@ -0,0 +1,392 @@ +{% extends "sysadmin/sys_org_info_base.html" %} +{% load seahub_tags i18n staticfiles %} + +{% block extra_style %} + +{% endblock %} + +{% block right_panel %} +
+ {% with cur_tab='traffic' %} + {% include 'sysadmin/snippets/sys_org_info_nav.html' %} + {% endwith %} +
+ +
+
+ + + +
+ +
+ + - + + + +
+
+ +
+ +
{# `
` is needed for ``, as the plugin requires. #} + +
+
+ +
+
+ +
+
+ +
+

+
+{% endblock %} + +{% block extra_script %} + + + +{% endblock %} diff --git a/seahub/templates/sysadmin/sys_org_info_user.html b/seahub/templates/sysadmin/sys_org_info_user.html index 63930f32d0..7f8f4c1dd6 100644 --- a/seahub/templates/sysadmin/sys_org_info_user.html +++ b/seahub/templates/sysadmin/sys_org_info_user.html @@ -3,12 +3,9 @@ {% block right_panel %}
- + {% with cur_tab='user' %} + {% include 'sysadmin/snippets/sys_org_info_nav.html' %} + {% endwith %}
diff --git a/seahub/templates/sysadmin/sys_statistic_file.html b/seahub/templates/sysadmin/sys_statistic_file.html index 2cbd4e115a..317db45ec7 100644 --- a/seahub/templates/sysadmin/sys_statistic_file.html +++ b/seahub/templates/sysadmin/sys_statistic_file.html @@ -13,9 +13,7 @@
  • {% trans "File" %}
  • {% trans "Storage" %}
  • {% trans "Users" %}
  • - {% if traffic_stats_enabled %} -
  • {% trans "Traffic" %}
  • - {% endif %} +
  • {% trans "Traffic" %}
  • diff --git a/seahub/templates/sysadmin/sys_statistic_storage.html b/seahub/templates/sysadmin/sys_statistic_storage.html index 4d0d428c41..b9a389295b 100644 --- a/seahub/templates/sysadmin/sys_statistic_storage.html +++ b/seahub/templates/sysadmin/sys_statistic_storage.html @@ -13,9 +13,7 @@
  • {% trans "File" %}
  • {% trans "Storage" %}
  • {% trans "Users" %}
  • - {% if traffic_stats_enabled %} -
  • {% trans "Traffic" %}
  • - {% endif %} +
  • {% trans "Traffic" %}
  • @@ -203,12 +201,21 @@ function renderChart(data, group_by) { right: 100 } }, + tooltips: { + callbacks: { + label: function(tooltipItem, data) { + return data.datasets[tooltipItem.datasetIndex].label + ': ' + + quotaSizeFormat(tooltipItem.yLabel); + } + } + }, scales: { yAxes: [{ ticks: { beginAtZero: true, + suggestedMax: 10*1000*1000, callback: function(value, index, values) { - return quotaSizeFormat(value, 2); + return quotaSizeFormat(value); } } }] diff --git a/seahub/templates/sysadmin/sys_statistic_traffic.html b/seahub/templates/sysadmin/sys_statistic_traffic.html new file mode 100644 index 0000000000..0901885b15 --- /dev/null +++ b/seahub/templates/sysadmin/sys_statistic_traffic.html @@ -0,0 +1,407 @@ +{% extends "sysadmin/base.html" %} +{% load seahub_tags i18n staticfiles %} + +{% block extra_style %} + +{% endblock %} + +{% block cur_statistic %}tab-cur{% endblock %} + +{% block right_panel %} +
    + +
    + +{% if traffic_stats_enabled %} + +{% endif %} + +
    +
    + + + +
    + +
    + + - + + + +
    +
    + +
    + +
    {# `
    ` is needed for ``, as the plugin requires. #} + +
    +
    + +
    +
    + +
    +
    + +
    +

    +
    +{% endblock %} + +{% block extra_script %} + + + +{% endblock %} diff --git a/seahub/templates/sysadmin/sys_statistic_user.html b/seahub/templates/sysadmin/sys_statistic_user.html index d3aae10a0b..0a55d93482 100644 --- a/seahub/templates/sysadmin/sys_statistic_user.html +++ b/seahub/templates/sysadmin/sys_statistic_user.html @@ -13,9 +13,7 @@
  • {% trans "File" %}
  • {% trans "Storage" %}
  • {% trans "Users" %}
  • - {% if traffic_stats_enabled %} -
  • {% trans "Traffic" %}
  • - {% endif %} +
  • {% trans "Traffic" %}
  • diff --git a/seahub/templates/sysadmin/sys_trafficadmin.html b/seahub/templates/sysadmin/sys_trafficadmin.html index 137791734d..2930fc3b01 100644 --- a/seahub/templates/sysadmin/sys_trafficadmin.html +++ b/seahub/templates/sysadmin/sys_trafficadmin.html @@ -10,10 +10,21 @@
  • {% trans "File" %}
  • {% trans "Storage" %}
  • {% trans "Users" %}
  • -
  • {% trans "Traffic" %}
  • +
  • {% trans "Traffic" %}
  • +{% if traffic_stats_enabled %} + +{% endif %} +

    {% trans "Tip: the traffic only includes the traffic used by sharing links." %}

    diff --git a/seahub/urls.py b/seahub/urls.py index 367585effb..4bfd078ea6 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -77,7 +77,9 @@ from seahub.api2.endpoints.admin.file_audit import FileAudit from seahub.api2.endpoints.admin.file_update import FileUpdate from seahub.api2.endpoints.admin.perm_audit import PermAudit from seahub.api2.endpoints.admin.sysinfo import SysInfo -from seahub.api2.endpoints.admin.statistics import FileOperationsView, TotalStorageView, ActiveUsersView +from seahub.api2.endpoints.admin.statistics import ( + FileOperationsView, TotalStorageView, ActiveUsersView, SystemTrafficView +) from seahub.api2.endpoints.admin.devices import AdminDevices from seahub.api2.endpoints.admin.device_errors import AdminDeviceErrors from seahub.api2.endpoints.admin.users import AdminUsers, AdminUser @@ -101,6 +103,7 @@ from seahub.api2.endpoints.admin.users_batch import AdminUsersBatch from seahub.api2.endpoints.admin.operation_logs import AdminOperationLogs from seahub.api2.endpoints.admin.organizations import AdminOrganization from seahub.api2.endpoints.admin.org_users import AdminOrgUsers, AdminOrgUser +from seahub.api2.endpoints.admin.org_stats import AdminOrgStatsTraffic from seahub.api2.endpoints.admin.logo import AdminLogo from seahub.api2.endpoints.admin.favicon import AdminFavicon from seahub.api2.endpoints.admin.license import AdminLicense @@ -320,6 +323,7 @@ urlpatterns = [ url(r'^api/v2.1/admin/statistics/file-operations/$', FileOperationsView.as_view(), name='api-v2.1-admin-statistics-file-operations'), url(r'^api/v2.1/admin/statistics/total-storage/$', TotalStorageView.as_view(), name='api-v2.1-admin-statistics-total-storage'), url(r'^api/v2.1/admin/statistics/active-users/$', ActiveUsersView.as_view(), name='api-v2.1-admin-statistics-active-users'), + url(r'^api/v2.1/admin/statistics/system-traffic/$', SystemTrafficView.as_view(), name='api-v2.1-admin-statistics-system-traffic'), ## admin::users url(r'^api/v2.1/admin/users/$', AdminUsers.as_view(), name='api-v2.1-admin-users'), @@ -393,6 +397,7 @@ urlpatterns = [ url(r'^api/v2.1/admin/organizations/(?P\d+)/$', AdminOrganization.as_view(), name='api-v2.1-admin-organization'), url(r'^api/v2.1/admin/organizations/(?P\d+)/users/$', AdminOrgUsers.as_view(), name='api-v2.1-admin-org-users'), url(r'^api/v2.1/admin/organizations/(?P\d+)/users/(?P[^/]+)/$', AdminOrgUser.as_view(), name='api-v2.1-admin-org-user'), + url(r'^api/v2.1/admin/organizations/(?P\d+)/statistics/traffic/$', AdminOrgStatsTraffic.as_view(), name='api-v2.1-admin-org-stats-traffic'), ## admin::logo url(r'^api/v2.1/admin/logo/$', AdminLogo.as_view(), name='api-v2.1-admin-logo'), @@ -428,6 +433,7 @@ urlpatterns = [ url(r'^sys/statistic/file/$', sys_statistic_file, name='sys_statistic_file'), url(r'^sys/statistic/storage/$', sys_statistic_storage, name='sys_statistic_storage'), url(r'^sys/statistic/user/$', sys_statistic_user, name='sys_statistic_user'), + url(r'^sys/statistic/traffic/$', sys_statistic_traffic, name='sys_statistic_traffic'), url(r'^sysadmin/#all-libs/$', fake_view, name='sys_repo_admin'), url(r'^sysadmin/#libs/(?P[-0-9a-f]{36})/$', fake_view, name='sys_admin_repo'), url(r'^sysadmin/#system-lib/$', fake_view, name='sys_list_system'), @@ -451,6 +457,7 @@ urlpatterns = [ url(r'^sys/orgadmin/(?P\d+)/user/$', sys_org_info_user, name='sys_org_info_user'), url(r'^sys/orgadmin/(?P\d+)/group/$', sys_org_info_group, name='sys_org_info_group'), url(r'^sys/orgadmin/(?P\d+)/library/$', sys_org_info_library, name='sys_org_info_library'), + url(r'^sys/orgadmin/(?P\d+)/traffic/$', sys_org_info_traffic, name='sys_org_info_traffic'), url(r'^sys/orgadmin/(?P\d+)/setting/$', sys_org_info_setting, name='sys_org_info_setting'), url(r'^sys/instadmin/$', sys_inst_admin, name='sys_inst_admin'), url(r'^sys/instadmin/(?P\d+)/remove/$', sys_inst_remove, name='sys_inst_remove'), diff --git a/seahub/utils/__init__.py b/seahub/utils/__init__.py index 94a7df4b15..614d58404d 100644 --- a/seahub/utils/__init__.py +++ b/seahub/utils/__init__.py @@ -716,6 +716,16 @@ if EVENTS_CONFIG_FILE: res = seafevents.get_total_storage_stats_by_day(session, start, end, offset) return res + def get_system_traffic_by_day(start, end, offset, op_type='all'): + with _get_seafevents_session() as session: + res = seafevents.get_system_traffic_by_day(session, start, end, offset, op_type) + return res + + def get_org_traffic_by_day(org_id, start, end, offset, op_type='all'): + with _get_seafevents_session() as session: + res = seafevents.get_org_traffic_by_day(session, org_id, start, end, offset, op_type) + return res + def get_file_update_events(email, org_id, repo_id, start, limit): """Return file update events list. (If no file update, return 'None') @@ -775,6 +785,10 @@ else: pass def get_total_storage_stats_by_day(): pass + def get_system_traffic_by_day(): + pass + def get_org_traffic_by_day(): + pass def get_file_update_events(): pass def get_perm_audit_events(): @@ -1310,7 +1324,7 @@ def send_perm_audit_msg(etype, from_user, to, repo_id, path, perm): msg_utf8 = msg.encode('utf-8') try: - seaserv.send_message('seahub.stats', msg_utf8) + seaserv.send_message('seahub.audit', msg_utf8) except Exception as e: logger.error("Error when sending perm-audit-%s message: %s" % (etype, str(e))) diff --git a/seahub/views/ajax.py b/seahub/views/ajax.py index 7bec5329bf..df9aadddd8 100644 --- a/seahub/views/ajax.py +++ b/seahub/views/ajax.py @@ -1198,7 +1198,7 @@ def get_file_upload_url_ul(request, token): username = request.user.username or request.session.get('anonymous_email') or '' - args = [repo_id, json.dumps({'anonymous_user': username}), 'upload', ''] + args = [repo_id, json.dumps({'anonymous_user': username}), 'upload-link', ''] kwargs = { 'use_onetime': False, } diff --git a/seahub/views/file.py b/seahub/views/file.py index 3c8757fb17..8e87a46c78 100644 --- a/seahub/views/file.py +++ b/seahub/views/file.py @@ -912,16 +912,9 @@ def _download_file_from_share_link(request, fileshare): return HttpResponseRedirect(next) send_file_access_msg(request, repo, real_path, 'share-link') - try: - file_size = seafile_api.get_file_size(repo.store_id, repo.version, - obj_id) - send_message('seahub.stats', 'file-download\t%s\t%s\t%s\t%s' % - (repo.id, shared_by, obj_id, file_size)) - except Exception as e: - logger.error('Error when sending file-download message: %s' % str(e)) dl_token = seafile_api.get_fileserver_access_token(repo.id, - obj_id, 'download', username, use_onetime=False) + obj_id, 'download-link', username, use_onetime=False) if not dl_token: messages.error(request, _(u'Unable to download file.')) @@ -1004,7 +997,10 @@ def view_shared_file(request, fileshare): next = request.META.get('HTTP_REFERER', settings.SITE_ROOT) return HttpResponseRedirect(next) - # view raw shared file, directly show/download file depends on browsers + send_file_access_msg(request, repo, path, 'share-link') + + # view raw shared file, directly show/download file depends on + # browsers return HttpResponseRedirect(raw_path) # preview file @@ -1551,14 +1547,19 @@ def view_raw_file(request, repo_id, file_path): return HttpResponseRedirect(raw_path) def send_file_access_msg(request, repo, path, access_from): - """Send file downlaod msg. + """Send file downlaod msg for audit. Arguments: - `request`: - `repo`: - `obj_id`: - - `access_from`: web or api + - `access_from`: web or api or share-link """ + access_from = access_from.lower() + if access_from not in ['web', 'api', 'share-link']: + logger.warn('Invalid access_from in file access msg: %s' % access_from) + return + username = request.user.username ip = get_remote_ip(request) @@ -1569,7 +1570,7 @@ def send_file_access_msg(request, repo, path, access_from): msg_utf8 = msg.encode('utf-8') try: - send_message('seahub.stats', msg_utf8) + send_message('seahub.audit', msg_utf8) except Exception as e: logger.error("Error when sending file-download-%s message: %s" % (access_from, str(e))) diff --git a/seahub/views/sysadmin.py b/seahub/views/sysadmin.py index 6fc9f1ff45..b376466528 100644 --- a/seahub/views/sysadmin.py +++ b/seahub/views/sysadmin.py @@ -143,6 +143,13 @@ def sys_statistic_user(request): return render(request, 'sysadmin/sys_statistic_user.html', { }) +@login_required +@sys_staff_required +def sys_statistic_traffic(request): + + return render(request, 'sysadmin/sys_statistic_traffic.html', { + }) + def can_view_sys_admin_repo(repo): default_repo_id = get_system_default_repo_id() is_default_repo = True if repo.id == default_repo_id else False @@ -1491,6 +1498,20 @@ def sys_org_info_library(request, org_id): return render(request, 'sysadmin/sys_org_info_library.html', org_basic_info) +@login_required +@sys_staff_required +def sys_org_info_traffic(request, org_id): + + org_id = int(org_id) + + if not ccnet_api.get_org_by_id(org_id): + raise Http404 + + org_basic_info = sys_get_org_base_info(org_id) + + return render(request, 'sysadmin/sys_org_info_traffic.html', + org_basic_info) + @login_required @sys_staff_required def sys_org_info_setting(request, org_id): diff --git a/tests/api/endpoints/admin/test_org_stats.py b/tests/api/endpoints/admin/test_org_stats.py new file mode 100644 index 0000000000..2851dad23b --- /dev/null +++ b/tests/api/endpoints/admin/test_org_stats.py @@ -0,0 +1,19 @@ +from django.core.urlresolvers import reverse + +from seahub.test_utils import BaseTestCase + +try: + from seahub.settings import LOCAL_PRO_DEV_ENV +except ImportError: + LOCAL_PRO_DEV_ENV = False + + +class AdminOrgStatsTrafficTest(BaseTestCase): + def test_get(self): + self.login_as(self.admin) + + url = reverse('api-v2.1-admin-org-stats-traffic', args=[1]) + url += '?start=2017-06-01 07:00:00&end=2017-06-03 07:00:00' + + resp = self.client.get(url) + self.assertEqual(200, resp.status_code) diff --git a/tests/api/endpoints/admin/test_statistics.py b/tests/api/endpoints/admin/test_statistics.py index 804446f03b..a7e4393004 100644 --- a/tests/api/endpoints/admin/test_statistics.py +++ b/tests/api/endpoints/admin/test_statistics.py @@ -65,3 +65,29 @@ class FileOperationsInfoText(BaseTestCase): self.assertEqual(200, resp.status_code) data = {'datetime': datetime_to_isoformat_timestr(datetime.datetime(2017, 6, 2, 3, 0)), 'total_storage': 13} assert data in json_resp + + @patch("seahub.api2.endpoints.admin.statistics.EVENTS_ENABLED") + @patch("seahub.api2.endpoints.admin.statistics.is_pro_version") + @patch("seahub.api2.endpoints.admin.statistics.get_system_traffic_by_day") + def test_can_get_system_traffic(self, mock_get_system_traffic_by_day, mock_is_pro, mock_events_enabled): + mock_get_system_traffic_by_day.return_value = [ + (datetime.datetime(2018, 8, 23, 0, 0), u'sync-file-download', 131793L), + (datetime.datetime(2018, 8, 23, 0, 0), u'web-file-download', 13L), + ] + mock_is_pro.return_value = True + mock_events_enabled = True + + url = reverse('api-v2.1-admin-statistics-system-traffic') + url += "?start=2018-08-20 07:00:00&end=2018-08-23 23:00:00" + resp = self.client.get(url) + json_resp = json.loads(resp.content) + self.assertEqual(200, resp.status_code) + + assert len(json_resp) == 4 + assert json_resp[0]['datetime'] == '2018-08-20T00:00:00+00:00' + assert json_resp[0]['web-file-download'] == 0 + assert json_resp[0]['sync-file-download'] == 0 + + assert json_resp[-1]['datetime'] == '2018-08-23T00:00:00+00:00' + assert json_resp[-1]['web-file-download'] == 13 + assert json_resp[-1]['sync-file-download'] == 131793