summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Zamotaev <nzamotaev@luxoft.com>2018-06-05 16:07:05 +0300
committerNikolay Zamotaev <nzamotaev@luxoft.com>2018-06-22 15:22:30 +0000
commite03e50b4e4d1a48d05ab48fb01769c35fe92d722 (patch)
tree4538a61a81303b8a9816924a95b12a389fa60907
parentfec257d2497ecaff5aa8071cc122b4cc8144caa3 (diff)
[deployment-server] Add tag support and filtering
Added tag support. Tags are parsed from packages: * extraMetadata * extraSignedMetadata Added parsing requires/conflicts tags from hello phase (Request goes in hello, filtering goes in app list) Change-Id: Ifab174bc3df0dbf4efa4832bb28bb4f58a6a302c Reviewed-by: Dominik Holland <dominik.holland@pelagicore.com>
-rw-r--r--README.md3
-rw-r--r--store/admin.py15
-rw-r--r--store/api.py29
-rw-r--r--store/migrations/0001_initial.py1
-rw-r--r--store/models.py2
-rw-r--r--store/utilities.py7
6 files changed, 53 insertions, 4 deletions
diff --git a/README.md b/README.md
index 9c32719..2b0aec9 100644
--- a/README.md
+++ b/README.md
@@ -139,6 +139,8 @@ Checks whether you are using the right Platform and the right API to communicate
| ---------- | ----------- |
| `platform` | The platform the client is running on, this sets the architecture of the packages you get. (see `settings.APPSTORE_PLATFORM`) |
| `version` | The Deployment Server HTTP API version you are using to communicate with the server. (see `settings.APPSTORE_VERSION`) |
+| `require_tag` | Optional parameter for filtering packages by tags. Receives coma-separated list of tags. Only applications containing any of specified tags should be listed. Tags must be alphanumeric. |
+| `conflicts_tag` | Optional parameter for filtering packages by tags. Receives coma-separated list of tags. No application containing any of the tags should be listed. Tags must be alphanumeric. |
Returns a JSON object:
@@ -148,6 +150,7 @@ Returns a JSON object:
| | `maintenance` | The Server is in maintenance mode and can't be used at the moment. |
| | `incompatible-platform` | You are using an incompatible Platform. |
| | `incompatible-version` | You are using an incompatible Version of the API. |
+| | `malformed-tag` | Tag had wrong format, was not alphanumeric or could not be parsed. |
## login
Does a login on the Server with the given username and password. Either a imei or a mac must be provided. This call is needed for downloading apps.
diff --git a/store/admin.py b/store/admin.py
index db2672b..0a34951 100644
--- a/store/admin.py
+++ b/store/admin.py
@@ -118,9 +118,10 @@ class CategoryAdmin(admin.ModelAdmin):
return redirect('admin:store_category_changelist')
+
class AppAdminForm(forms.ModelForm):
class Meta:
- exclude = ["id", "name"]
+ exclude = ["id", "name", "tags"]
appId = ""
name = ""
@@ -175,12 +176,22 @@ class AppAdminForm(forms.ModelForm):
m = super(AppAdminForm, self).save(commit);
m.id = self.appId
m.name = self.name
+
+ m.file.seek(0)
+ pkgdata = parseAndValidatePackageMetadata(m.file)
+ taglist = set()
+ for fields in ('extra','extraSigned'):
+ if fields in pkgdata['header']:
+ if 'tags' in pkgdata['header'][fields]:
+ tags = set(pkgdata['header'][fields]['tags']) #Fill tags list then add them
+ taglist = taglist.union(tags)
+ m.tags = ",".join(taglist)
return m
class AppAdmin(admin.ModelAdmin):
form = AppAdminForm
- list_display = ('name',)
+ list_display = ('name', 'id')
def save_model(self, request, obj, form, change):
obj.save()
diff --git a/store/api.py b/store/api.py
index 5e1620e..9bb8dc2 100644
--- a/store/api.py
+++ b/store/api.py
@@ -36,12 +36,13 @@ import shutil
import json
from django.conf import settings
+from django.db.models import Q
from django.http import HttpResponse, HttpResponseForbidden, Http404, JsonResponse
from django.contrib import auth
from django.template import Context, loader
from models import App, Category, Vendor
-from utilities import parsePackageMetadata, packagePath, iconPath, downloadPath, addSignatureToPackage
+from utilities import parsePackageMetadata, packagePath, iconPath, downloadPath, addSignatureToPackage, validateTag
def hello(request):
@@ -54,6 +55,14 @@ def hello(request):
elif request.REQUEST.get("version", "") != str(settings.APPSTORE_PLATFORM_VERSION):
status = 'incompatible-version'
+ for j in ("require_tag", "conflicts_tag",):
+ if j in request.REQUEST: #Tags are coma-separated,
+ taglist = [i.lower() for i in request.REQUEST[j].split(',') if i]
+ for i in taglist:
+ if not validateTag(i): #Tags must be alphanumeric (or, even better - limited to ASCII alphanumeric)
+ status = 'malformed-tag'
+ break
+ request.session[j] = taglist
return JsonResponse({'status': status})
@@ -101,11 +110,27 @@ def appList(request):
if catId != -1: # All metacategory
apps = apps.filter(category__exact = catId)
- appList = list(apps.values('id', 'name', 'vendor__name', 'briefDescription', 'category'))
+ #Tag filtering
+ #"require_tag", "conflicts_tag"
+ # Tags are combined by logical AND (for require) and logical OR for conflicts
+ if 'require_tag' in request.session:
+ for i in request.session['require_tag']:
+ regex = '(^|,)%s(,|$)' % (i,)
+ apps = apps.filter(Q(tags__regex = regex))
+ if 'conflicts_tag' in request.session:
+ for i in request.session['conflicts_tag']:
+ regex = '(^|,)%s(,|$)' % (i,)
+ apps = apps.filter(~Q(tags__regex = regex))
+
+ appList = list(apps.values('id', 'name', 'vendor__name', 'briefDescription', 'category', 'tags').order_by('id'))
for app in appList:
app['category_id'] = app['category']
app['category'] = Category.objects.all().filter(id__exact = app['category_id'])[0].name
app['vendor'] = app['vendor__name']
+ if app['tags'] != "":
+ app['tags'] = app['tags'].split(',')
+ else:
+ app['tags'] = []
del app['vendor__name']
# this is not valid JSON, since we are returning a list!
diff --git a/store/migrations/0001_initial.py b/store/migrations/0001_initial.py
index 3c85e9d..474d3af 100644
--- a/store/migrations/0001_initial.py
+++ b/store/migrations/0001_initial.py
@@ -54,6 +54,7 @@ class Migration(migrations.Migration):
('description', models.TextField()),
('dateAdded', models.DateField(auto_now_add=True)),
('dateModified', models.DateField(auto_now=True)),
+ ('tags', models.TextField(blank=True)),
],
options={
},
diff --git a/store/models.py b/store/models.py
index 4d87f70..7335ab2 100644
--- a/store/models.py
+++ b/store/models.py
@@ -122,6 +122,7 @@ class App(models.Model):
description = models.TextField()
dateAdded = models.DateField(auto_now_add = True)
dateModified = models.DateField(auto_now = True)
+ tags = models.TextField(blank=True)
def __unicode__(self):
return self.name + " [" + self.id + "]"
@@ -134,3 +135,4 @@ class App(models.Model):
except:
pass
super(App, self).save(*args, **kwargs)
+
diff --git a/store/utilities.py b/store/utilities.py
index 1b68f6a..a464507 100644
--- a/store/utilities.py
+++ b/store/utilities.py
@@ -45,6 +45,13 @@ from OpenSSL.crypto import load_pkcs12, FILETYPE_PEM, dump_privatekey, dump_cert
from django.conf import settings
+def validateTag(tag):
+ for i in tag:
+ if not i.isalnum():
+ if i != "_":
+ return False
+ return True
+
def packagePath(appId = None):
path = settings.MEDIA_ROOT + 'packages/'
if appId is not None: