mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-13 05:39:59 +00:00
@@ -3860,3 +3860,12 @@ img.thumbnail {
|
|||||||
width:800px;
|
width:800px;
|
||||||
overflow:auto;
|
overflow:auto;
|
||||||
}
|
}
|
||||||
|
/* system info */
|
||||||
|
.license-file-upload {
|
||||||
|
margin-top:5px;
|
||||||
|
position:relative;
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
.license-file-upload-btn {
|
||||||
|
white-space:nowrap;
|
||||||
|
}
|
||||||
|
45
seahub/api2/endpoints/admin/license.py
Normal file
45
seahub/api2/endpoints/admin/license.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Copyright (c) 2012-2016 Seafile Ltd.
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
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 rest_framework import status
|
||||||
|
from seaserv import ccnet_api
|
||||||
|
|
||||||
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
|
from seahub.api2.throttling import UserRateThrottle
|
||||||
|
from seahub.api2.utils import api_error
|
||||||
|
from seahub.settings import LICENSE_PATH
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AdminLicense(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
throttle_classes = (UserRateThrottle, )
|
||||||
|
permission_classes = (IsAdminUser,)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
license_file = request.FILES.get('license', None)
|
||||||
|
if not license_file:
|
||||||
|
error_msg = 'license invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
license_dir = os.path.dirname(LICENSE_PATH)
|
||||||
|
try:
|
||||||
|
if not os.path.exists(license_dir):
|
||||||
|
error_msg = 'path %s invalid.' % LICENSE_PATH
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
with open(LICENSE_PATH, 'w') as fd:
|
||||||
|
fd.write(license_file.read())
|
||||||
|
|
||||||
|
ccnet_api.reload_license()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Interal Server Eerror'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
return Response({'success': True}, status=status.HTTP_200_OK)
|
@@ -415,6 +415,9 @@ SITE_TITLE = 'Private Seafile'
|
|||||||
# Base name used in email sending
|
# Base name used in email sending
|
||||||
SITE_NAME = 'Seafile'
|
SITE_NAME = 'Seafile'
|
||||||
|
|
||||||
|
# Path to the license file(relative to the media path)
|
||||||
|
LICENSE_PATH = os.path.join(PROJECT_ROOT, '../../seafile-license.txt')
|
||||||
|
|
||||||
# Path to the favicon file (relative to the media path)
|
# Path to the favicon file (relative to the media path)
|
||||||
# tip: use a different name when modify it.
|
# tip: use a different name when modify it.
|
||||||
FAVICON_PATH = 'img/favicon.ico'
|
FAVICON_PATH = 'img/favicon.ico'
|
||||||
|
@@ -93,7 +93,7 @@
|
|||||||
<% } %>
|
<% } %>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/template" id="sysinfo-header-tmpl">
|
<script type="text/template" id="sysinfo-tmpl">
|
||||||
<div class="header-bar">
|
<div class="header-bar">
|
||||||
<h3 class="">{% trans "Info" %}</h3>
|
<h3 class="">{% trans "Info" %}</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -102,16 +102,20 @@
|
|||||||
<span class="loading-icon loading-tip"></span>
|
<span class="loading-icon loading-tip"></span>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/template" id="sysinfo-tmpl">
|
<script type="text/template" id="sysinfo-con-tmpl">
|
||||||
<dl>
|
<dl>
|
||||||
<dt>{% trans "System Info" %}</dt>
|
<dt>{% trans "System Info" %}</dt>
|
||||||
<dd><% if (is_pro) { %>
|
<dd>
|
||||||
|
<% if (is_pro) { %>
|
||||||
{% trans "Professional Edition" %}
|
{% trans "Professional Edition" %}
|
||||||
<% if (with_license) { %>
|
<% if (with_license) { %>
|
||||||
{% trans "licensed to" %} <%- license_to %>
|
{% trans "licensed to" %} <%- license_to %>,
|
||||||
,
|
|
||||||
{% trans "expires on" %} <%- license_expiration %>
|
{% trans "expires on" %} <%- license_expiration %>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
<div class="license-file-upload">
|
||||||
|
<input type="file" name="license" class="license-file-upload-input transparent-file-input" />
|
||||||
|
<button type="button" class="license-file-upload-btn">{% trans "Upload licence" %}</button>
|
||||||
|
</div>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
{% trans "Community Edition" %}
|
{% trans "Community Edition" %}
|
||||||
<a href="http://manual.seafile.com/deploy_pro/migrate_from_seafile_community_server.html" target="_blank">{% trans "Upgrade to Pro Edition" %}</a>
|
<a href="http://manual.seafile.com/deploy_pro/migrate_from_seafile_community_server.html" target="_blank">{% trans "Upgrade to Pro Edition" %}</a>
|
||||||
|
@@ -73,6 +73,7 @@ from seahub.api2.endpoints.admin.logs import AdminLogs
|
|||||||
from seahub.api2.endpoints.admin.org_users import AdminOrgUsers, AdminOrgUser
|
from seahub.api2.endpoints.admin.org_users import AdminOrgUsers, AdminOrgUser
|
||||||
from seahub.api2.endpoints.admin.logo import AdminLogo
|
from seahub.api2.endpoints.admin.logo import AdminLogo
|
||||||
from seahub.api2.endpoints.admin.favicon import AdminFavicon
|
from seahub.api2.endpoints.admin.favicon import AdminFavicon
|
||||||
|
from seahub.api2.endpoints.admin.license import AdminLicense
|
||||||
|
|
||||||
# Uncomment the next two lines to enable the admin:
|
# Uncomment the next two lines to enable the admin:
|
||||||
#from django.contrib import admin
|
#from django.contrib import admin
|
||||||
@@ -300,6 +301,7 @@ urlpatterns = patterns(
|
|||||||
## admin::logo
|
## admin::logo
|
||||||
url(r'^api/v2.1/admin/logo/$', AdminLogo.as_view(), name='api-v2.1-admin-logo'),
|
url(r'^api/v2.1/admin/logo/$', AdminLogo.as_view(), name='api-v2.1-admin-logo'),
|
||||||
url(r'^api/v2.1/admin/favicon/$', AdminFavicon.as_view(), name='api-v2.1-admin-favicon'),
|
url(r'^api/v2.1/admin/favicon/$', AdminFavicon.as_view(), name='api-v2.1-admin-favicon'),
|
||||||
|
url(r'^api/v2.1/admin/license/$', AdminLicense.as_view(), name='api-v2.1-admin-license'),
|
||||||
|
|
||||||
(r'^avatar/', include('seahub.avatar.urls')),
|
(r'^avatar/', include('seahub.avatar.urls')),
|
||||||
(r'^notification/', include('seahub.notifications.urls')),
|
(r'^notification/', include('seahub.notifications.urls')),
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
# Copyright (c) 2012-2016 Seafile Ltd.
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from seahub.utils import is_pro_version
|
from seahub.utils import is_pro_version
|
||||||
@@ -9,7 +8,7 @@ from seaserv import ccnet_api
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def get_license_path():
|
def get_license_path():
|
||||||
return os.path.join(settings.PROJECT_ROOT, '../../seafile-license.txt')
|
return settings.LICENSE_PATH
|
||||||
|
|
||||||
def parse_license():
|
def parse_license():
|
||||||
"""Parse license file and return dict.
|
"""Parse license file and return dict.
|
||||||
@@ -32,9 +31,8 @@ def parse_license():
|
|||||||
"""
|
"""
|
||||||
ret = {}
|
ret = {}
|
||||||
lines = []
|
lines = []
|
||||||
license_path = get_license_path()
|
|
||||||
try:
|
try:
|
||||||
with open(license_path) as f:
|
with open(get_license_path()) as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(e)
|
logger.warn(e)
|
||||||
|
@@ -189,6 +189,8 @@ define([
|
|||||||
case 'admin_shares': return siteRoot + 'api/v2.1/admin/shares/';
|
case 'admin_shares': return siteRoot + 'api/v2.1/admin/shares/';
|
||||||
case 'sys_group_admin_export_excel': return siteRoot + 'sys/groupadmin/export-excel/';
|
case 'sys_group_admin_export_excel': return siteRoot + 'sys/groupadmin/export-excel/';
|
||||||
case 'admin-logs': return siteRoot + 'api/v2.1/admin/admin-logs/';
|
case 'admin-logs': return siteRoot + 'api/v2.1/admin/admin-logs/';
|
||||||
|
|
||||||
|
case 'license': return siteRoot + 'api/v2.1/admin/license/';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -12,15 +12,48 @@ define([
|
|||||||
id: "admin-dashboard",
|
id: "admin-dashboard",
|
||||||
|
|
||||||
template: _.template($("#sysinfo-tmpl").html()),
|
template: _.template($("#sysinfo-tmpl").html()),
|
||||||
headerTemplate: _.template($("#sysinfo-header-tmpl").html()),
|
conTemplate: _.template($("#sysinfo-con-tmpl").html()),
|
||||||
|
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
this.sysinfo = new SysInfo();
|
this.sysinfo = new SysInfo();
|
||||||
this.render();
|
this.render();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'change .license-file-upload-input': 'uploadLicenseFile'
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadLicenseFile: function() {
|
||||||
|
var $input = this.$('.license-file-upload-input');
|
||||||
|
var file;
|
||||||
|
if ($input[0].files) {
|
||||||
|
file = $input[0].files[0];
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var input_name = $input.attr('name');
|
||||||
|
var fd = new FormData();
|
||||||
|
|
||||||
|
fd.append(input_name, file);
|
||||||
|
$.ajax({
|
||||||
|
url: Common.getUrl({'name': 'license'}),
|
||||||
|
type: 'POST',
|
||||||
|
data: fd,
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
beforeSend: Common.prepareCSRFToken,
|
||||||
|
success: function(){
|
||||||
|
location.reload(true);
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
Common.ajaxErrorHandler(xhr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
this.$el.html(this.headerTemplate());
|
this.$el.html(this.template());
|
||||||
this.$loadingTip = this.$('.loading-tip');
|
this.$loadingTip = this.$('.loading-tip');
|
||||||
this.$sysinfo = this.$('.sysinfo');
|
this.$sysinfo = this.$('.sysinfo');
|
||||||
},
|
},
|
||||||
@@ -59,11 +92,22 @@ define([
|
|||||||
this.showSysinfo();
|
this.showSysinfo();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setLicenceUploadUI: function() {
|
||||||
|
var $btn = this.$('.license-file-upload-btn');
|
||||||
|
this.$('.license-file-upload').css({
|
||||||
|
'width': $btn.outerWidth()
|
||||||
|
});
|
||||||
|
this.$('.license-file-upload-input').css({
|
||||||
|
'height': $btn.outerHeight()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.$loadingTip.hide();
|
this.$loadingTip.hide();
|
||||||
var json_data = this.sysinfo.toJSON();
|
var json_data = this.sysinfo.toJSON();
|
||||||
json_data['formatted_storage'] = Common.quotaSizeFormat(json_data['total_storage'], 1)
|
json_data['formatted_storage'] = Common.quotaSizeFormat(json_data['total_storage'], 1)
|
||||||
this.$sysinfo.html(this.template(json_data));
|
this.$sysinfo.html(this.conTemplate(json_data));
|
||||||
|
this.setLicenceUploadUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
29
tests/api/endpoints/admin/test_license.py
Normal file
29
tests/api/endpoints/admin/test_license.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import os
|
||||||
|
import json
|
||||||
|
from mock import patch
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
|
from seahub.api2.endpoints.admin import license as license_api
|
||||||
|
from seahub.settings import LICENSE_PATH
|
||||||
|
from seahub.test_utils import BaseTestCase
|
||||||
|
from tests.common.utils import urljoin
|
||||||
|
from tests.common.common import BASE_URL
|
||||||
|
|
||||||
|
|
||||||
|
class AdminLicenseTest(BaseTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.login_as(self.admin)
|
||||||
|
|
||||||
|
@patch.object(license_api, 'ccnet_api')
|
||||||
|
def test_update_license(self, mock_ccnet_api):
|
||||||
|
mock_ccnet_api.return_val = {}
|
||||||
|
|
||||||
|
url = reverse('api-v2.1-admin-license')
|
||||||
|
url = urljoin(BASE_URL, url)
|
||||||
|
with open(
|
||||||
|
os.path.join(os.getcwd(), 'tests/seahub/utils/seafile-license.txt')) as f:
|
||||||
|
json_resp = self.client.post(url, {'license': f})
|
||||||
|
json_resp = json.loads(json_resp.content)
|
||||||
|
|
||||||
|
assert json_resp['success'] is True
|
||||||
|
assert os.path.exists(LICENSE_PATH)
|
Reference in New Issue
Block a user