mirror of
https://github.com/dkmstr/openuds.git
synced 2025-02-02 09:47:13 +03:00
Finished (i hope... :-) ) Image Gallery & Service Pools usage
This commit is contained in:
parent
42845e6243
commit
97787b7eba
@ -91,7 +91,7 @@ class Images(ModelHandler):
|
||||
def item_as_dict_overview(self, item):
|
||||
return {
|
||||
'id': item.uuid,
|
||||
'size': '{}x{}, {} bytes'.format(item.width, item.height, len(item.data)),
|
||||
'size': '{}x{}, {} bytes (thumb {} bytes)'.format(item.width, item.height, len(item.data), len(item.thumb)),
|
||||
'name': item.name,
|
||||
'thumb': item.thumb64,
|
||||
}
|
||||
|
@ -33,7 +33,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
from uds.models import DeployedService, OSManager, Service
|
||||
from uds.models import DeployedService, OSManager, Service, Image
|
||||
from uds.core.ui.images import DEFAULT_THUMB_BASE64
|
||||
from uds.core.util.State import State
|
||||
from uds.core.util import log
|
||||
from uds.REST.model import ModelHandler
|
||||
@ -56,7 +57,8 @@ class ServicesPools(ModelHandler):
|
||||
'publications': Publications,
|
||||
}
|
||||
|
||||
save_fields = ['name', 'comments', 'service_id', 'osmanager_id', 'initial_srvs', 'cache_l1_srvs', 'cache_l2_srvs', 'max_srvs']
|
||||
save_fields = ['name', 'comments', 'service_id', 'osmanager_id', 'image_id', 'initial_srvs', 'cache_l1_srvs', 'cache_l2_srvs', 'max_srvs']
|
||||
remove_fields = ['osmanager_id', 'service_id']
|
||||
|
||||
table_title = _('Service Pools')
|
||||
table_fields = [
|
||||
@ -69,6 +71,8 @@ class ServicesPools(ModelHandler):
|
||||
table_row_style = {'field': 'state', 'prefix': 'row-state-'}
|
||||
|
||||
def item_as_dict(self, item):
|
||||
# if item does not have an associated service, hide it (the case, for example, for a removed service)
|
||||
# Access from dict will raise an exception, and item will be skipped
|
||||
val = {
|
||||
'id': item.uuid,
|
||||
'name': item.name,
|
||||
@ -76,6 +80,7 @@ class ServicesPools(ModelHandler):
|
||||
'state': item.state,
|
||||
'service_id': item.service.uuid,
|
||||
'provider_id': item.service.provider.uuid,
|
||||
'image_id': item.image.uuid if item.image is not None else None,
|
||||
'initial_srvs': item.initial_srvs,
|
||||
'cache_l1_srvs': item.cache_l1_srvs,
|
||||
'cache_l2_srvs': item.cache_l2_srvs,
|
||||
@ -89,6 +94,18 @@ class ServicesPools(ModelHandler):
|
||||
|
||||
return val
|
||||
|
||||
def item_as_dict_overview(self, item):
|
||||
# if item does not have an associated service, hide it (the case, for example, for a removed service)
|
||||
# Access from dict will raise an exception, and item will be skipped
|
||||
return {
|
||||
'id': item.uuid,
|
||||
'name': item.name,
|
||||
'comments': item.comments,
|
||||
'state': item.state,
|
||||
'thumb': item.image.thumb64 if item.image is not None else DEFAULT_THUMB_BASE64,
|
||||
'service_id': item.service.uuid
|
||||
}
|
||||
|
||||
# Gui related
|
||||
def getGui(self, type_):
|
||||
if OSManager.objects.count() < 1: # No os managers, can't create db
|
||||
@ -114,34 +131,41 @@ class ServicesPools(ModelHandler):
|
||||
'type': gui.InputField.CHOICE_TYPE,
|
||||
'rdonly': True,
|
||||
'order': 101, # At end
|
||||
}, {
|
||||
'name': 'image_id',
|
||||
'values': [gui.choiceItem(-1, '')] + [gui.choiceItem(v.uuid, v.name) for v in Image.objects.all()],
|
||||
'label': ugettext('Associated Image'),
|
||||
'tooltip': ugettext('Image assocciated with this service'),
|
||||
'type': gui.InputField.CHOICE_TYPE,
|
||||
'order': 102, # At end
|
||||
}, {
|
||||
'name': 'initial_srvs',
|
||||
'value': '0',
|
||||
'label': ugettext('Initial available services'),
|
||||
'tooltip': ugettext('Services created initially for this service pool'),
|
||||
'type': gui.InputField.NUMERIC_TYPE,
|
||||
'order': 102, # At end
|
||||
'order': 103, # At end
|
||||
}, {
|
||||
'name': 'cache_l1_srvs',
|
||||
'value': '0',
|
||||
'label': ugettext('Services to keep in cache'),
|
||||
'tooltip': ugettext('Services keeped in cache for improved user service assignation'),
|
||||
'type': gui.InputField.NUMERIC_TYPE,
|
||||
'order': 103, # At end
|
||||
'order': 104, # At end
|
||||
}, {
|
||||
'name': 'cache_l2_srvs',
|
||||
'value': '0',
|
||||
'label': ugettext('Services to keep in L2 cache'),
|
||||
'tooltip': ugettext('Services keeped in cache of level2 for improved service generation'),
|
||||
'type': gui.InputField.NUMERIC_TYPE,
|
||||
'order': 104, # At end
|
||||
'order': 105, # At end
|
||||
}, {
|
||||
'name': 'max_srvs',
|
||||
'value': '0',
|
||||
'label': ugettext('Maximum number of services to provide'),
|
||||
'tooltip': ugettext('Maximum number of service (assigned and L1 cache) that can be created for this service'),
|
||||
'type': gui.InputField.NUMERIC_TYPE,
|
||||
'order': 105, # At end
|
||||
'order': 106, # At end
|
||||
}]:
|
||||
self.addField(g, f)
|
||||
|
||||
@ -153,8 +177,7 @@ class ServicesPools(ModelHandler):
|
||||
try:
|
||||
try:
|
||||
service = Service.objects.get(uuid=fields['service_id'])
|
||||
del fields['service_id']
|
||||
fields['service'] = service
|
||||
fields['service_id'] = service.id
|
||||
except:
|
||||
raise RequestError(ugettext('Base service does not exists anymore'))
|
||||
|
||||
@ -162,8 +185,9 @@ class ServicesPools(ModelHandler):
|
||||
serviceType = service.getType()
|
||||
if serviceType.needsManager is True:
|
||||
osmanager = OSManager.objects.get(uuid=fields['osmanager_id'])
|
||||
fields['osmanager'] = osmanager
|
||||
del fields['osmanager_id']
|
||||
fields['osmanager_id'] = osmanager.id
|
||||
else:
|
||||
del fields['osmanager_id']
|
||||
|
||||
if serviceType.usesCache is False:
|
||||
for k in ('initial_srvs', 'cache_l1_srvs', 'cache_l2_srvs', 'max_srvs'):
|
||||
@ -172,6 +196,16 @@ class ServicesPools(ModelHandler):
|
||||
except Exception:
|
||||
raise RequestError(ugettext('This service requires an os manager'))
|
||||
|
||||
imgId = fields['image_id']
|
||||
fields['image_id'] = None
|
||||
logger.debug('Image id: {}'.format(imgId))
|
||||
try:
|
||||
if imgId != '-1':
|
||||
image = Image.objects.get(uuid=imgId)
|
||||
fields['image_id'] = image.id
|
||||
except Exception:
|
||||
logger.exception('At image recovering')
|
||||
|
||||
except (RequestError, ResponseError):
|
||||
raise
|
||||
except Exception as e:
|
||||
|
@ -47,7 +47,7 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__updated__ = '2014-11-05'
|
||||
__updated__ = '2014-11-06'
|
||||
|
||||
|
||||
# a few constants
|
||||
@ -432,6 +432,8 @@ class ModelHandler(BaseModelHandler):
|
||||
detail = None # Dictionary containing detail routing
|
||||
# Put needed fields
|
||||
save_fields = []
|
||||
# Put removable fields before updating
|
||||
remove_fields = []
|
||||
# Table info needed fields and title
|
||||
table_fields = []
|
||||
table_row_style = {}
|
||||
@ -579,8 +581,9 @@ class ModelHandler(BaseModelHandler):
|
||||
for item in self.model.objects.filter(*args, **kwargs):
|
||||
try:
|
||||
yield self.item_as_dict_overview(item)
|
||||
except Exception:
|
||||
logger.exception('Exception getting item from {0}'.format(self.model))
|
||||
except Exception: # maybe an exception is thrown to skip an item
|
||||
# logger.exception('Exception getting item from {0}'.format(self.model))
|
||||
pass
|
||||
|
||||
def get(self):
|
||||
'''
|
||||
@ -597,9 +600,12 @@ class ModelHandler(BaseModelHandler):
|
||||
if nArgs == 0:
|
||||
result = []
|
||||
for val in self.model.objects.all():
|
||||
res = self.item_as_dict(val)
|
||||
self.fillIntanceFields(val, res)
|
||||
result.append(res)
|
||||
try:
|
||||
res = self.item_as_dict(val)
|
||||
self.fillIntanceFields(val, res)
|
||||
result.append(res)
|
||||
except Exception: # maybe an exception is thrown to skip an item
|
||||
pass
|
||||
return result
|
||||
|
||||
# if has custom methods, look for if this request matches any of them
|
||||
@ -703,6 +709,9 @@ class ModelHandler(BaseModelHandler):
|
||||
else: # Must have 1 arg
|
||||
# We have to take care with this case, update will efectively update records on db
|
||||
item = self.model.objects.get(uuid=self._args[0].upper())
|
||||
for v in self.remove_fields:
|
||||
if v in args:
|
||||
del args[v]
|
||||
item.__dict__.update(args) # Update fields from args
|
||||
except self.model.DoesNotExist:
|
||||
raise NotFound('Item not found')
|
||||
|
40
server/src/uds/core/ui/images.py
Normal file
40
server/src/uds/core/ui/images.py
Normal file
File diff suppressed because one or more lines are too long
@ -55,7 +55,7 @@ class Image(UUIDModel):
|
||||
|
||||
'''
|
||||
MAX_IMAGE_SIZE = (128, 128)
|
||||
THUMBNAIL_SIZE = (32, 32)
|
||||
THUMBNAIL_SIZE = (48, 48)
|
||||
|
||||
name = models.CharField(max_length=128, unique=True, db_index=True)
|
||||
stamp = models.DateTimeField() # Date creation or validation of this entry. Set at write time
|
||||
@ -73,7 +73,7 @@ class Image(UUIDModel):
|
||||
|
||||
@staticmethod
|
||||
def encode64(data):
|
||||
return base64.encodestring(data)[:-1] # Removes trailing \n
|
||||
return base64.encodestring(data).replace('\n', '') # Removes \n
|
||||
|
||||
@staticmethod
|
||||
def decode64(data64):
|
||||
@ -166,11 +166,11 @@ class Image(UUIDModel):
|
||||
return HttpResponse(self.data, content_type='image/png')
|
||||
|
||||
def thumbnailResponse(self):
|
||||
return HttpResponse(self.data, content_type='image/png')
|
||||
return HttpResponse(self.thumb, content_type='image/png')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.stamp = getSqlDatetime()
|
||||
return UUIDModel.save(self, *args, **kwargs)
|
||||
|
||||
def __unicode__(self):
|
||||
return 'Image "{}", {} bytes'.format(self.name, len(self.data))
|
||||
return 'Image id {}, name {}, {} bytes, {} bytes thumb'.format(self.id, self.name, len(self.data), len(self.thumb))
|
||||
|
@ -2,38 +2,55 @@ gui.gallery = new GuiElement(api.gallery, "imgal")
|
||||
gui.gallery.link = ->
|
||||
"use strict"
|
||||
|
||||
newImage = (meth, table, refreshFnc) ->
|
||||
api.templates.get "new_image", (tmpl) ->
|
||||
content = api.templates.evaluate(tmpl,
|
||||
)
|
||||
modalId = gui.launchModal(gettext("New image"), content,
|
||||
actionButton: "<button type=\"button\" class=\"btn btn-success button-accept\">" + gettext("Upload") + "</button>"
|
||||
)
|
||||
gui.tools.applyCustoms modalId
|
||||
$(modalId + " .button-accept").click ->
|
||||
file = $('#id-image_for_gallery')[0].files[0]
|
||||
name = $('#id_image_name').val()
|
||||
if name == ""
|
||||
name = file.name
|
||||
newEditImageFnc = (forEdit) ->
|
||||
realFnc = (value, refreshFnc) ->
|
||||
api.templates.get "new_image", (tmpl) ->
|
||||
content = api.templates.evaluate(tmpl,
|
||||
)
|
||||
modalId = gui.launchModal(gettext("New image"), content,
|
||||
actionButton: "<button type=\"button\" class=\"btn btn-success button-accept\">" + gettext("Upload") + "</button>"
|
||||
)
|
||||
gui.doLog value.name
|
||||
gui.tools.applyCustoms modalId
|
||||
value is null or $("#id_image_name").val(value.name)
|
||||
$(modalId + " .button-accept").click ->
|
||||
file = $('#id-image_for_gallery')[0].files[0]
|
||||
|
||||
if file.size > 256*1024
|
||||
gui.notify gettext("Image is too big (max. upload size is 256Kb)")
|
||||
return
|
||||
if file is null
|
||||
gui.notify gettext("You must select an image")
|
||||
return
|
||||
|
||||
name = $('#id_image_name').val()
|
||||
if name == ""
|
||||
name = file.name
|
||||
|
||||
$(modalId).modal "hide"
|
||||
reader = new FileReader()
|
||||
if file.size > 256*1024
|
||||
gui.notify gettext("Image is too big (max. upload size is 256Kb)")
|
||||
return
|
||||
|
||||
reader.onload = (res) ->
|
||||
img = res.target.result
|
||||
img = img.substr img.indexOf("base64,") + 7
|
||||
data = {
|
||||
data: img
|
||||
name: name
|
||||
}
|
||||
api.gallery.create data, refreshFnc
|
||||
$(modalId).modal "hide"
|
||||
reader = new FileReader()
|
||||
|
||||
reader.readAsDataURL(file)
|
||||
reader.onload = (res) ->
|
||||
img = res.target.result
|
||||
img = img.substr img.indexOf("base64,") + 7
|
||||
data = {
|
||||
data: img
|
||||
name: name
|
||||
}
|
||||
if value is null
|
||||
api.gallery.create data, refreshFnc
|
||||
else
|
||||
data.id = value.id
|
||||
api.gallery.save data, refreshFnc
|
||||
|
||||
reader.readAsDataURL(file)
|
||||
if forEdit is true
|
||||
(value, event, table, refreshFnc) ->
|
||||
realFnc value, refreshFnc
|
||||
else
|
||||
(meth, table, refreshFnc) ->
|
||||
realFnc null, refreshFnc
|
||||
|
||||
api.templates.get "gallery", (tmpl) ->
|
||||
gui.clearWorkspace()
|
||||
@ -45,9 +62,11 @@ gui.gallery.link = ->
|
||||
rowSelect: "single"
|
||||
buttons: [
|
||||
"new"
|
||||
"edit"
|
||||
"delete"
|
||||
]
|
||||
onNew: newImage
|
||||
onNew: newEditImageFnc false
|
||||
onEdit: newEditImageFnc true
|
||||
onDelete: gui.methods.del(gui.gallery, gettext("Delete Image"), gettext("Image deletion error"))
|
||||
return
|
||||
|
||||
|
@ -59,10 +59,7 @@ gui.servicesPools.link = (event) ->
|
||||
$cacheL2Fld.prop "disabled", "disabled"
|
||||
else
|
||||
$cacheL2Fld.prop "disabled", false
|
||||
if data.info.needs_publication is false
|
||||
$publishOnSaveFld.bootstrapSwitch "setDisabled", true
|
||||
else
|
||||
$publishOnSaveFld.bootstrapSwitch "setDisabled", false
|
||||
$publishOnSaveFld.bootstrapSwitch "toggleReadonly", data.info.needs_publication
|
||||
$osmFld.selectpicker "refresh" if $osmFld.hasClass("selectpicker")
|
||||
return
|
||||
|
||||
@ -448,12 +445,14 @@ gui.servicesPools.link = (event) ->
|
||||
onData: (data) ->
|
||||
gui.doLog "onData", data
|
||||
$.each data, (index, value) ->
|
||||
gui.doLog value.thumb
|
||||
try
|
||||
service = availableServices[value.service_id]
|
||||
if not service?
|
||||
value.parent = gettext("undefined")
|
||||
return
|
||||
style = "display:inline-block; background: url(data:image/png;base64," + service.info.icon + "); background-size: 16px 16px; background-repeat: no-repeat; width: 16px; height: 16px; vertical-align: middle;"
|
||||
style = "display:inline-block; background: url(data:image/png;base64," + value.thumb + "); background-size: 16px 16px; background-repeat: no-repeat; width: 16px; height: 16px; vertical-align: middle;"
|
||||
gui.doLog style
|
||||
if value.restrained
|
||||
value.name = "<span class=\"fa fa-exclamation text-danger\"></span> " + value.name
|
||||
value.state = gettext("Restrained")
|
||||
|
@ -7,7 +7,7 @@
|
||||
<input id="id_image_name" name="image_name" type="text" class="form-control" placeholder="{% trans 'Image name' %}" autofocus required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" data-toggle="tooltip" data-title="{% trans 'Name of the image. If left empty, will get the filename as name'%}">{% trans 'Image name' %}</label>
|
||||
<label class="col-sm-3 control-label" data-toggle="tooltip" data-title="{% trans 'Name of the image. If left empty, will get the filename as name'%}">{% trans 'Image' %}</label>
|
||||
<div class="fileinput fileinput-new" data-provides="fileinput">
|
||||
<div class="fileinput-preview thumbnail" data-trigger="fileinput" style="width: {{ size.0 }}px; height: {{ size.1 }}px;"></div>
|
||||
<div>
|
||||
|
@ -39,13 +39,14 @@ from django.template import RequestContext
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.views.decorators.http import last_modified
|
||||
from django.views.decorators.cache import cache_page
|
||||
from django.views.decorators.cache import cache_page, cache_control
|
||||
from django.views.i18n import javascript_catalog
|
||||
from django.utils import timezone
|
||||
from django.contrib.staticfiles import finders
|
||||
|
||||
from uds.core.auths.auth import webLogin, webLogout, webLoginRequired, authenticate, webPassword, authenticateViaCallback, authLogLogin, authLogLogout, getUDSCookie
|
||||
from uds.models import Authenticator, DeployedService, Transport, UserService, Network, Image
|
||||
from uds.core.ui.images import DEFAULT_IMAGE
|
||||
from uds.web.forms.LoginForm import LoginForm
|
||||
from uds.core.managers.UserServiceManager import UserServiceManager
|
||||
from uds.core.managers.UserPrefsManager import UserPrefsManager
|
||||
@ -331,7 +332,6 @@ def sernotify(request, idUserService, notification):
|
||||
return HttpResponse('ok', content_type='text/plain')
|
||||
|
||||
|
||||
@cache_page(60 * 10) # Cache images 10 minutes
|
||||
def transportIcon(request, idTrans):
|
||||
try:
|
||||
icon = Transport.objects.get(uuid=idTrans).getInstance().icon(False)
|
||||
@ -340,7 +340,6 @@ def transportIcon(request, idTrans):
|
||||
return HttpResponseRedirect('/static/img/unknown.png')
|
||||
|
||||
|
||||
@cache_page(60 * 10) # Cache images 10 minutes
|
||||
def serviceImage(request, idImage):
|
||||
try:
|
||||
icon = Image.objects.get(uuid=idImage)
|
||||
@ -352,12 +351,7 @@ def serviceImage(request, idImage):
|
||||
icon = Transport.objects.get(uuid=idImage).getInstance().icon(False)
|
||||
return HttpResponse(icon, content_type='image/png')
|
||||
except Exception:
|
||||
result = finders.find('img/uds-service.png')
|
||||
if isinstance(result, (list, tuple)):
|
||||
result = result[0]
|
||||
with open(result) as f:
|
||||
icon = f.read()
|
||||
return HttpResponse(icon, content_type='image/png')
|
||||
return HttpResponse(DEFAULT_IMAGE, content_type='image/png')
|
||||
|
||||
|
||||
@transformId
|
||||
|
Loading…
x
Reference in New Issue
Block a user