Commit 49ddc7ec authored by BERJON Matthieu's avatar BERJON Matthieu
Browse files

Merge branch 'webapp-privacy-fixes' into 'django'

Webapp privacy fixes

See merge request !151
parents f923722a aedd3283
Pipeline #46373 failed with stage
in 46 seconds
......@@ -9,7 +9,7 @@ RUN apt-getq update && apt-getq install \
nginx-light zip gcc python3-dev python3-pip python3-wheel python3-mysqldb \
python-mysqldb python3-crypto gunicorn3 python3-redis python-mysqldb \
python3-crypto python3-natsort python3-aiohttp python3-aioredis supervisor \
python3-ipy python3-django-taggit python3-iso8601
python3-ipy python3-django-taggit python3-iso8601 python3-robot-detection
COPY requirements.txt /tmp/
RUN cd /tmp && pip3 install -r requirements.txt && rm requirements.txt
......
......@@ -7,6 +7,7 @@ import re
import redis
import IPy
from django.conf import settings
from django.db.models import Q
import config
from .models import Job, Webapp, AllgoUser
......@@ -201,3 +202,14 @@ def get_request_user(request):
"user", None)
def query_webapps_for_user(user):
"""Return a queryset of all webapps visible by a given user"""
if user.is_superuser:
return Webapp.objects.all()
else:
# select webapps that are either public or owned by the user
return Webapp.objects.filter(Q(private=False) | Q(user_id=user.id))
......@@ -11,6 +11,7 @@ Attributes:
# Python standard libraries
import glob
import io
import itertools
import json
import logging
import re
......@@ -24,11 +25,13 @@ import zipfile
import iso8601
import natsort
import requests
import robot_detection
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
......@@ -68,7 +71,7 @@ from .forms import (
)
# Local imports
import config
from .helpers import get_base_url, get_ssh_data, upload_data, notify_controller, lookup_job_file, get_request_user
from .helpers import get_base_url, get_ssh_data, upload_data, notify_controller, lookup_job_file, get_request_user, query_webapps_for_user
from .mixins import IsProviderMixin, JobAuthMixin
from .models import (
AllgoUser,
......@@ -172,8 +175,9 @@ class WebappList(ListView):
context_object_name = 'webapps'
paginate_by = 10
template_name = 'webapp_list.html'
queryset = Webapp.objects.filter(private=0).order_by('-created_at')
def get_queryset(self):
return query_webapps_for_user(self.request.user).order_by('-created_at')
class UserWebappList(ListView):
"""List of user's webapp
......@@ -723,7 +727,32 @@ class TagList(ListView):
Each tag return as well the number of webapps attached to it
"""
tags = Tag.objects.annotate(num_tag=Count('taggit_taggeditem_items'))
# Compute the list of tags with the count of webapps visible by this user
#
# We need a raw request because filtering on Count() is not supported
# in django 1.11.
#
# In django>=2.0 we should be able to write something like:
# tags = Tag.objects.annotate(num_tag=Count('taggit_taggeditem_items',
# filter = Q(...)))
#
# list of webapp ids visible by the current user
webapp_ids = tuple(itertools.chain(
*query_webapps_for_user(self.request.user).values_list("id")))
# webapp content id (to select onl the tags on Webapp objects)
webapp_content_id = ContentType.objects.get(app_label="main", model="Webapp").id
# compute the list of tags with the webapp count (in the webapp_ids subset)
tags = Tag.objects.raw("""
SELECT taggit_tag.*, count(*) as num_tag
FROM taggit_tag JOIN taggit_taggeditem
ON taggit_tag.id=taggit_taggeditem.tag_id
WHERE content_type_id=%s AND object_id in %s
GROUP BY tag_id
""", (webapp_content_id, webapp_ids))
return tags
......@@ -743,7 +772,8 @@ class TagWebappList(ListView):
template_name = 'tag_webapp_list.html'
def get_queryset(self):
return Webapp.objects.filter(tags__slug=self.kwargs['slug'])
return query_webapps_for_user(self.request.user
).filter(tags__slug=self.kwargs['slug'])
def get_context_data(self, **kwargs):
return super().get_context_data(tag=self.kwargs["slug"], **kwargs)
......@@ -1038,6 +1068,16 @@ class JobCreate(SuccessMessageMixin, CreateView):
webapp = Webapp.objects.get(docker_name=self.kwargs['docker_name'])
kwargs['webapp'] = webapp
# Private apps should not be indexed by search engines
#
# -> return 404 if we detect a robot
# (but we let authenticated user through, so that the app is still
# usable if robot_detection gets broken)
if (webapp.private and self.request.user.is_anonymous() and
robot_detection.is_robot(
self.request.META.get("HTTP_USER_AGENT") or " ")):
raise Http404
# Check if a readme is declared in the database
if webapp.readme:
readme_file = os.path.join(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment