mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-24 21:34:41 +03:00
Merged from 2.1
This commit is contained in:
commit
3f110fb6c6
@ -46,6 +46,8 @@ from uds.models import Authenticator, User, Group
|
||||
from uds.core.auths.User import User as aUser
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds.REST import RequestError
|
||||
from uds.core.ui.images import DEFAULT_THUMB_BASE64
|
||||
from .user_services import AssignedService
|
||||
|
||||
from uds.REST.model import DetailHandler
|
||||
|
||||
@ -55,9 +57,16 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
# Details of /auth
|
||||
|
||||
def getPoolsForGroups(groups):
|
||||
for g in groups:
|
||||
for servicePool in g.deployedServices.all():
|
||||
yield servicePool
|
||||
|
||||
|
||||
class Users(DetailHandler):
|
||||
|
||||
custom_methods = ['servicesPools', 'userServices']
|
||||
|
||||
@staticmethod
|
||||
def uuid_to_id(iterator):
|
||||
for v in iterator:
|
||||
@ -166,9 +175,40 @@ class Users(DetailHandler):
|
||||
|
||||
return 'deleted'
|
||||
|
||||
def servicesPools(self, parent, item):
|
||||
uuid = processUuid(item)
|
||||
user = parent.users.get(uuid=processUuid(uuid))
|
||||
res = []
|
||||
for i in getPoolsForGroups(user.groups.all()):
|
||||
res.append({
|
||||
'id': i.uuid,
|
||||
'name': i.name,
|
||||
'thumb': i.image.thumb64 if i.image is not None else DEFAULT_THUMB_BASE64,
|
||||
'user_services_count': i.userServices.count(),
|
||||
'state': _('With errors') if i.isRestrained() else _('Ok'),
|
||||
})
|
||||
|
||||
return res
|
||||
|
||||
def userServices(self, parent, item):
|
||||
uuid = processUuid(item)
|
||||
user = parent.users.get(uuid=processUuid(uuid))
|
||||
res = []
|
||||
for i in user.userServices.all():
|
||||
if i.state == State.USABLE:
|
||||
v = AssignedService.itemToDict(i)
|
||||
v['pool'] = i.deployed_service.name
|
||||
v['pool_id'] = i.deployed_service.uuid
|
||||
res.append(v)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
|
||||
class Groups(DetailHandler):
|
||||
|
||||
custom_methods = ['servicesPools']
|
||||
|
||||
def getItems(self, parent, item):
|
||||
try:
|
||||
multi = False
|
||||
@ -287,3 +327,18 @@ class Groups(DetailHandler):
|
||||
self.invalidItemException()
|
||||
|
||||
return 'deleted'
|
||||
|
||||
def servicesPools(self, parent, item):
|
||||
uuid = processUuid(item)
|
||||
group = parent.groups.get(uuid=processUuid(uuid))
|
||||
res = []
|
||||
for i in getPoolsForGroups((group,)):
|
||||
res.append({
|
||||
'id': i.uuid,
|
||||
'name': i.name,
|
||||
'thumb': i.image.thumb64 if i.image is not None else DEFAULT_THUMB_BASE64,
|
||||
'user_services_count': i.userServices.count(),
|
||||
'state': _('With errors') if i.isRestrained() else _('Ok'),
|
||||
})
|
||||
|
||||
return res
|
||||
|
@ -63,7 +63,7 @@ from datetime import datetime, timedelta
|
||||
import logging
|
||||
import pickle
|
||||
|
||||
__updated__ = '2017-01-20'
|
||||
__updated__ = '2017-01-23'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -44,8 +44,8 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
if values is not None:
|
||||
if values['domain'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide a domain!'))
|
||||
if values['domain'].find('.') == -1:
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide domain in FQDN'))
|
||||
# if values['domain'].find('.') == -1:
|
||||
# raise osmanagers.OSManager.ValidationException(_('Must provide domain in FQDN'))
|
||||
if values['account'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide an account to add machines to domain!'))
|
||||
if values['account'].find('\\') != -1:
|
||||
|
@ -1,7 +1,7 @@
|
||||
# jshint strict: true
|
||||
# jshint strict: true
|
||||
((api, $, undefined_) ->
|
||||
"use strict"
|
||||
api.tools =
|
||||
api.tools =
|
||||
base64: (s) ->
|
||||
window.btoa unescape(encodeURIComponent(s))
|
||||
input2timeStamp: (inputDate, inputTime) ->
|
||||
@ -36,7 +36,7 @@
|
||||
capitalize: (str) ->
|
||||
str = str.toLowerCase()
|
||||
return str.substr(0,1).toUpperCase() + str.substr(1)
|
||||
|
||||
|
||||
return str
|
||||
|
||||
isEmpty: (obj) ->
|
||||
@ -110,7 +110,7 @@ localizedStrftime = (locale) ->
|
||||
# - timezone [number] timezone offset in minutes from GMT
|
||||
_strftime = (fmt, d, locale, options) ->
|
||||
options = options or {}
|
||||
|
||||
|
||||
# d and locale are optional so check if d is really the locale
|
||||
if d and not quacksLikeDate(d)
|
||||
locale = d
|
||||
@ -118,13 +118,13 @@ _strftime = (fmt, d, locale, options) ->
|
||||
d = d or new Date()
|
||||
locale = locale or DefaultLocale
|
||||
locale.formats = locale.formats or {}
|
||||
|
||||
|
||||
# Hang on to this Unix timestamp because we might mess with it directly
|
||||
# below.
|
||||
timestamp = d.getTime()
|
||||
d = dateToUTC(d) if options.utc or typeof options.timezone is "number"
|
||||
d = new Date(d.getTime() + (options.timezone * 60000)) if typeof options.timezone is "number"
|
||||
|
||||
|
||||
# Most of the specifiers supported by C's strftime, and some from Ruby.
|
||||
# Some other syntax extensions from Ruby are supported: %-, %_, and %0
|
||||
# to pad with nothing, space, or zero (respectively).
|
||||
@ -133,20 +133,20 @@ _strftime = (fmt, d, locale, options) ->
|
||||
padding = null
|
||||
if c.length is 2
|
||||
mod = c[0]
|
||||
|
||||
|
||||
# omit padding
|
||||
if mod is "-"
|
||||
padding = ""
|
||||
|
||||
|
||||
# pad with space
|
||||
else if mod is "_"
|
||||
padding = " "
|
||||
|
||||
|
||||
# pad with zero
|
||||
else if mod is "0"
|
||||
padding = "0"
|
||||
else
|
||||
|
||||
|
||||
# unrecognized, return the format
|
||||
return _
|
||||
c = c[1]
|
||||
@ -256,17 +256,17 @@ quacksLikeDate = (x) ->
|
||||
|
||||
# Default padding is '0' and default length is 2, both are optional.
|
||||
pad = (n, padding, length) ->
|
||||
|
||||
|
||||
# pad(n, <length>)
|
||||
if typeof padding is "number"
|
||||
length = padding
|
||||
padding = "0"
|
||||
|
||||
|
||||
# Defaults handle pad(n) and pad(n, <padding>)
|
||||
padding ?= "0"
|
||||
length ?= 2
|
||||
s = String(n)
|
||||
|
||||
|
||||
# padding may be an empty string, don't loop forever if it is
|
||||
s = padding + s while s.length < length if padding
|
||||
s
|
||||
@ -295,7 +295,7 @@ ordinal = (n) ->
|
||||
# Pilfered & ported from Ruby's strftime implementation.
|
||||
weekNumber = (d, firstWeekday) ->
|
||||
firstWeekday = firstWeekday or "sunday"
|
||||
|
||||
|
||||
# This works by shifting the weekday back by one day if we
|
||||
# are treating Monday as the first day of the week.
|
||||
wday = d.getDay()
|
||||
|
@ -174,8 +174,10 @@ gui.authenticators.link = (event) ->
|
||||
id = selected[0].id
|
||||
type = gui.authenticators.types[selected[0].type]
|
||||
gui.doLog "Type", type
|
||||
user = new GuiElement(api.authenticators.detail(id, "users", { permission: selected[0].permission }), "users")
|
||||
group = new GuiElement(api.authenticators.detail(id, "groups", { permission: selected[0].permission }), "groups")
|
||||
userAPI = api.authenticators.detail(id, "users", { permission: selected[0].permission })
|
||||
user = new GuiElement(userAPI, "users")
|
||||
groupAPI = api.authenticators.detail(id, "groups", { permission: selected[0].permission })
|
||||
group = new GuiElement(groupAPI, "groups")
|
||||
grpTable = group.table(
|
||||
icon: 'groups'
|
||||
container: "groups-placeholder"
|
||||
@ -292,6 +294,127 @@ gui.authenticators.link = (event) ->
|
||||
# New button will only be shown on authenticators that can create new users
|
||||
usrButtons = [
|
||||
"edit"
|
||||
{
|
||||
text: gui.tools.iconAndText( 'fa-info', gettext('Information') )
|
||||
css: "disabled"
|
||||
disabled: true
|
||||
|
||||
click: (vals, value, btn, tbl, refreshFnc) ->
|
||||
|
||||
if vals.length > 1
|
||||
return
|
||||
|
||||
val = vals[0]
|
||||
userAPI.invoke val.id + "/servicesPools", (pools) ->
|
||||
userAPI.invoke val.id + "/userServices", (userServices) ->
|
||||
user.rest.item val.id, (item) ->
|
||||
group.rest.overview (groups) -> # Get groups
|
||||
gui.doLog "Pools", pools
|
||||
api.templates.get "user-info", (tmpl) ->
|
||||
content = api.templates.evaluate(tmpl,
|
||||
id: 'information',
|
||||
groups_all: groups
|
||||
groups: item.groups
|
||||
pools: pools,
|
||||
userServices: userServices,
|
||||
goClass: 'goLink'
|
||||
)
|
||||
modalId = gui.launchModal(gettext('User information'), content,
|
||||
actionButton: " "
|
||||
)
|
||||
|
||||
$('#information-groups-table').DataTable(
|
||||
colReorder: true
|
||||
stateSave: true
|
||||
paging: true
|
||||
info: false
|
||||
autoWidth: false
|
||||
lengthChange: false
|
||||
pageLength: 10
|
||||
|
||||
columnDefs: [
|
||||
{ 'width': '100%', 'targets': 0 },
|
||||
]
|
||||
|
||||
ordering: true
|
||||
order: [[ 0, 'asc' ]]
|
||||
|
||||
dom: '<>fr<"uds-table"t>ip'
|
||||
|
||||
language: gui.config.dataTablesLanguage
|
||||
)
|
||||
|
||||
|
||||
$('#information-pools-table').DataTable(
|
||||
colReorder: true
|
||||
stateSave: true
|
||||
paging: true
|
||||
info: false
|
||||
autoWidth: false
|
||||
lengthChange: false
|
||||
pageLength: 10
|
||||
|
||||
columnDefs: [
|
||||
{ 'width': '50%', 'targets': 0 },
|
||||
{ 'width': '120px', 'targets': 1 },
|
||||
{ 'width': '40px', 'targets': 2 },
|
||||
{ 'width': '160px', 'targets': 3 },
|
||||
]
|
||||
|
||||
ordering: true
|
||||
order: [[ 1, 'asc' ]]
|
||||
|
||||
dom: '<>fr<"uds-table"t>ip'
|
||||
|
||||
language: gui.config.dataTablesLanguage
|
||||
)
|
||||
|
||||
$('#information-userservices-table').DataTable(
|
||||
colReorder: true
|
||||
stateSave: true
|
||||
paging: true
|
||||
info: false
|
||||
autoWidth: false
|
||||
lengthChange: false
|
||||
pageLength: 10
|
||||
|
||||
columnDefs: [
|
||||
{ 'width': '25%', 'targets': 0 },
|
||||
{ 'width': '25%', 'targets': 1 },
|
||||
{ 'width': '120px', 'targets': 2 },
|
||||
{ 'width': '20%', 'targets': 3 },
|
||||
{ 'width': '20%', 'targets': 4 },
|
||||
]
|
||||
|
||||
ordering: true
|
||||
order: [[ 1, 'asc' ]]
|
||||
|
||||
dom: '<>fr<"uds-table"t>ip'
|
||||
|
||||
language: gui.config.dataTablesLanguage
|
||||
)
|
||||
|
||||
$('.goLink').on('click', (event) ->
|
||||
$this = $(this);
|
||||
event.preventDefault();
|
||||
gui.lookupUuid = $this.attr('href').substr(1)
|
||||
$(modalId).modal('hide')
|
||||
setTimeout( ->
|
||||
$(".lnk-deployed_services").click();
|
||||
, 500);
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
select: (vals, value, btn, tbl, refreshFnc) ->
|
||||
unless vals.length == 1
|
||||
$(btn).addClass("disabled").prop('disabled', true)
|
||||
return
|
||||
|
||||
$(btn).removeClass("disabled").prop('disabled', false)
|
||||
return
|
||||
|
||||
}
|
||||
"delete"
|
||||
"xls"
|
||||
]
|
||||
|
@ -3,9 +3,6 @@ gui.providers = new GuiElement(api.providers, "provi")
|
||||
gui.providers.link = (event) ->
|
||||
"use strict"
|
||||
|
||||
iconAndText = (icon, text) ->
|
||||
'<span class="fa ' + icon + '"> </span> <span class="label-tbl-button">' + text + '</span>'
|
||||
|
||||
# Button definition to trigger "Test" action
|
||||
testButton = testButton:
|
||||
text: gettext("Test")
|
||||
@ -112,7 +109,7 @@ gui.providers.link = (event) ->
|
||||
"new"
|
||||
"edit"
|
||||
{
|
||||
text: iconAndText( 'fa-info', gettext('Information') )
|
||||
text: gui.tools.iconAndText( 'fa-info', gettext('Information') )
|
||||
css: "disabled"
|
||||
disabled: true
|
||||
click: (vals, value, btn, tbl, refreshFnc) ->
|
||||
@ -204,7 +201,7 @@ gui.providers.link = (event) ->
|
||||
"edit"
|
||||
{
|
||||
permission: api.permissions.MANAGEMENT
|
||||
text: iconAndText('fa-ambulance', gettext("Maintenance"))
|
||||
text: gui.tools.iconAndText('fa-ambulance', gettext("Maintenance"))
|
||||
css: "disabled"
|
||||
disabled: true
|
||||
click: (vals, value, btn, tbl, refreshFnc) ->
|
||||
@ -230,14 +227,14 @@ gui.providers.link = (event) ->
|
||||
select: (vals, value, btn, tbl, refreshFnc) ->
|
||||
unless vals.length == 1
|
||||
$(btn).removeClass("btn-warning").removeClass("btn-info").addClass("disabled").prop('disabled', true)
|
||||
$(btn).empty().append(iconAndText('fa-ambulance', gettext("Maintenance")))
|
||||
$(btn).empty().append(gui.tools.iconAndText('fa-ambulance', gettext("Maintenance")))
|
||||
return
|
||||
val = vals[0]
|
||||
if val.maintenance_mode is false
|
||||
content = iconAndText('fa-ambulance', gettext('Enter maintenance Mode'))
|
||||
content = gui.tools.iconAndText('fa-ambulance', gettext('Enter maintenance Mode'))
|
||||
cls = 'btn-warning'
|
||||
else
|
||||
content = iconAndText('fa-truck',gettext('Exit Maintenance Mode'))
|
||||
content = gui.tools.iconAndText('fa-truck',gettext('Exit Maintenance Mode'))
|
||||
cls = 'btn-info'
|
||||
|
||||
$(btn).removeClass("disabled").addClass(cls).prop('disabled', false)
|
||||
|
@ -173,4 +173,7 @@
|
||||
(data, type, full) ->
|
||||
levels[data] or "OTHER"
|
||||
|
||||
iconAndText: (icon, text) ->
|
||||
'<span class="fa ' + icon + '"> </span> <span class="label-tbl-button">' + text + '</span>'
|
||||
|
||||
return
|
||||
|
@ -193,6 +193,7 @@
|
||||
{% js_template 'providers' %}
|
||||
{% js_template 'service-info' %}
|
||||
{% js_template 'authenticators' %}
|
||||
{% js_template 'user-info' %}
|
||||
{% js_template 'osmanagers' %}
|
||||
{% js_template 'connectivity' %}
|
||||
{% js_template 'services_pool' %}
|
||||
|
86
server/src/uds/templates/uds/admin/tmpl/user-info.html
Normal file
86
server/src/uds/templates/uds/admin/tmpl/user-info.html
Normal file
@ -0,0 +1,86 @@
|
||||
{% load i18n html5 %}
|
||||
{% verbatim %}
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active in"><a href="#{{ id }}-overview_tab" data-toggle="tab">{% endverbatim %}{% trans 'Groups' %}{% verbatim %}</a></li>
|
||||
<li><a href="#{{ id }}-pools_tab" data-toggle="tab">{% endverbatim %}{% trans 'Services Pools' %}{% verbatim %}</a></li>
|
||||
<li><a href="#{{ id }}-uservices_tab" data-toggle="tab">{% endverbatim %}{% trans 'Assigned Services' %}{% verbatim %}</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade in active" id="{{ id }}-overview_tab">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<table id="{{ id }}-groups-table" style="width:100%;" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% endverbatim %}{% trans 'Group' %}{% verbatim %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each groups_all }}
|
||||
{{# ifbelongs id ../groups }}
|
||||
<tr>
|
||||
<td>{{ name }}</td>
|
||||
</tr>
|
||||
{{/ ifbelongs }}
|
||||
{{/each }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="{{ id }}-pools_tab">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<table id="{{ id }}-pools-table" style="width:100%;" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% endverbatim %}{% trans 'Pool' %}{% verbatim %}</th>
|
||||
<th>{% endverbatim %}{% trans 'State' %}{% verbatim %}</th>
|
||||
<th>{% endverbatim %}{% trans 'Image' %}{% verbatim %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each pools }}
|
||||
<tr>
|
||||
<td>{{ name }}<span style="float: right;"><a href="#{{ id }}" class="{{ ../goClass }}"><i class="fa fa-external-link"> </i></a></span></td>
|
||||
<td>{{ state }}</td>
|
||||
<td><img src="data:image/png;base64,{{ thumb }}" style="width: 32px; height: auto;"/></td>
|
||||
<td>{{ user_services_count }}</td>
|
||||
</tr>
|
||||
{{/each }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="{{ id }}-uservices_tab">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<table id="{{ id }}-userservices-table" style="width:100%;" class="display">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% endverbatim %}{% trans 'Unique ID' %}{% verbatim %}</th>
|
||||
<th>{% endverbatim %}{% trans 'Friendly Name' %}{% verbatim %}</th>
|
||||
<th>{% endverbatim %}{% trans 'In Use' %}{% verbatim %}</th>
|
||||
<th>{% endverbatim %}{% trans 'IP' %}{% verbatim %}</th>
|
||||
<th>{% endverbatim %}{% trans 'Service Pool' %}{% verbatim %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each userServices }}
|
||||
<tr>
|
||||
<td>{{ unique_id }}</td>
|
||||
<td>{{ friendly_name }}</td>
|
||||
<td>{{#if in_use }}{% endverbatim %}{% trans 'Yes' %}{% verbatim %}{{ else }}{% endverbatim %}{% trans 'No' %}{% verbatim %}{{/if }}</td>
|
||||
<td>{{ ip }}</td>
|
||||
<td>{{ pool }}<span style="float: right;"><a href="#{{ pool_id }}" class="{{ ../goClass }}"><i class="fa fa-external-link"> </i></a></span></td>
|
||||
</tr>
|
||||
{{/each }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endverbatim %}
|
@ -9,30 +9,30 @@
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2 bg-primary img-rounded">
|
||||
<h3>{% trans 'Download UDS Plugin for' %} {{ os|osName }}</h3>
|
||||
<p>{% trans 'In order to be able to execute UDS services, you need to have UDS plugin installed.' %}</p>
|
||||
<p>{% trans 'In order to be able to execute UDS services, you need to download and install UDS Plugin.' %}</p>
|
||||
<div class="text-center">{{ os|pluginDownloadUrl|safe }}</div>
|
||||
<h3>{% trans 'Or download another version' %}</h3>
|
||||
<p>{% trans 'If your platform couldn’t be detected correctly, you can manually download the version required for your Operating System.' %}</p>
|
||||
<h3>{% trans 'Or download for other operating system' %}</h3>
|
||||
<p>{% trans 'In case that your operating system has not been correctly detected, you can download manually from' %}</p>
|
||||
<p>
|
||||
{% if os != 'linux' %}
|
||||
<p class="text-center">
|
||||
<a href="{% url 'uds.web.views.client_downloads' os='Linux' %}" class="btn btn-warning">{% trans 'Linux UDS plugin' %}</a>
|
||||
<a href="{% url 'uds.web.views.client_downloads' os='Linux' %}" class="btn btn-warning">{% trans 'Download Linux UDS plugin' %}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if os != 'windows' %}
|
||||
<p class="text-center">
|
||||
<a href="{% url 'uds.web.views.client_downloads' os='Windows' %}" class="btn btn-warning">{% trans 'Windows UDS plugin' %}</a>
|
||||
<a href="{% url 'uds.web.views.client_downloads' os='Windows' %}" class="btn btn-warning">{% trans 'Download Windows UDS plugin' %}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if os != 'mac' %}
|
||||
<p class="text-center">
|
||||
<a href="{% url 'uds.web.views.client_downloads' os='Mac' %}" class="btn btn-warning">{% trans 'Mac OSX (>10.5) UDS plugin' %}</a>
|
||||
<a href="{% url 'uds.web.views.client_downloads' os='Mac' %}" class="btn btn-warning">{% trans 'Download Mac OS X (>10.5) UDS plugin' %}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% if request.user %}
|
||||
<p>{% trans 'If you already have UDS Plugin installed and you can still see this message, you can disable automatic detection here.' %}</p>
|
||||
<p>{% trans 'If you already have UDS Plugin installed but this message persists to appear, you can disable automatic detection here' %}</p>
|
||||
<p>
|
||||
<form>
|
||||
<select id="plugin" class="selectpicker show-menu-arrow" data-width="100%" data-size="2" style="display: none;">
|
||||
|
@ -211,11 +211,11 @@ def ifbrowser(parser, token):
|
||||
@register.filter(name='osName')
|
||||
def osName(os):
|
||||
if os == 'windows':
|
||||
return 'Windows platform'
|
||||
return 'Windows'
|
||||
elif os == 'linux':
|
||||
return 'Linux platform'
|
||||
return 'Linux'
|
||||
else:
|
||||
return 'Mac OSX platform'
|
||||
return 'Mac OS X'
|
||||
|
||||
|
||||
@register.filter(name='pluginDownloadUrl')
|
||||
|
Loading…
Reference in New Issue
Block a user