def _get_subject_perms(self, user_obj, obj): if obj.hmac is not None: # A hmac can only ever grant read if obj.is_hmac_valid(): return self.JUST_READ return set() if "user/%s" % user_obj.username == obj.path: return self.ALL try: # Get the thing associated with this user userthing = Thing.objects.get(pathid=Thing.hash("user/%s" % user_obj.username)) # Check if this event is associated with an admin annotation via eventtag or eventsourcetag t = obj.thing if t is not None: Thing.objects.get(id=t.id, relatedthing__thing=userthing, eventtag__annotation="admin") return self.ALL except Thing.DoesNotExist: # One or more of the things we were looking for doesn't exist, therefore therefore there is only read. pass # If we got this far, and this is a user Thing then read should be denied if obj.is_user(): return set() # could do something more sophisticated here, but just at the moment there is no need. return self.JUST_READ
def get(self, request, thing, depth="0"): if not request.user.has_perm( Thing.PERM_READ, ThingSubject(fullpath=thing, depth=depth)): return HttpResponseForbidden("Denied") hashid = Thing.hash(thing) try: thing = Thing.objects.get(pathid=hashid) # create a url with a hmac in it if the thing is a user. If not just a simple url will do. thingsubject = ThingSubject(thing=thing) if thingsubject.is_user(): hmac = thingsubject.create_hmac() ics_feed_url = reverse("export ics hmac", kwargs={ "thing": thing.fullpath, "hmac": hmac }) else: ics_feed_url = reverse("export ics", kwargs={"thing": thing.fullpath}) context = { "thing": Thing.objects.get(pathid=hashid), "ics_feed_url": ics_feed_url } return render(request, "calendar.html", context) except Thing.DoesNotExist: return HttpResponseNotFound()
def get(self, request, thing, depth="0"): if not request.user.has_perm( Thing.PERM_READ, ThingSubject(fullpath=thing, depth=depth)): return HttpResponseForbidden("Denied") hashid = Thing.hash(thing) try: if depth == "0": thing = Thing.objects.get(pathid=hashid) typeofthing = thing.type if typeofthing is None: typeofthing = "default" context = {"thing": thing} try: return render(request, "student/things/thing-%s.html" % typeofthing, context) except: return render(request, "student/things/thing-default.html", context) else: depth = int(depth) if depth > 10 or depth < 0: return HttpResponseBadRequest( "Sorry no more than 10 levels allowed") things = Thing.objects.filter( Thing.treequery([thing], max_depth=depth)).order_by("fullname") return render(request, "student/list-of-things.html", {"things": things}) except Thing.DoesNotExist: return HttpResponseNotFound()
def get_user_thing(self, request, thing): if (request.user.is_authenticated() and self.get_user_permission(request, thing)): return Thing.objects.get(pathid=Thing.hash(thing)) elif thing == self.public_user_path: return None raise PermissionDenied
def create_module(self, path, name, shortname): """ Creates a module in the database. Will not create Things above module level, and will fail if the path is not unique. """ # find the parent (remove end slash) try: parent = self.thing_list.get(pathid=Thing.hash(path[:-1])) except Thing.DoesNotExist: self.logger.log( 'failed', 'module', 'Could not find path {0}'.format(path[:-1]) ) return except Thing.MultipleObjectsReturned: self.logger.log( 'failed', 'module', 'Path {0} was not unique'.format(path[:-1]) ) return db_module = Thing( fullname=name, type='module', parent=parent, name=shortname ) self.logger.log('insert', 'module', name) db_module.save() return db_module
def get(self, request, thing, hmac=None): if not request.user.has_perm(Thing.PERM_READ, ThingSubject(fullpath=thing, hmac=hmac)): return HttpResponseForbidden("Denied") hashid = Thing.hash(thing) outputformat = request.path.split(".")[-1] try: thing = Thing.objects.get(pathid=hashid) if outputformat in settings.EVENT_EXPORTERS: exporter_class = settings.EVENT_EXPORTERS[outputformat] exporter = newinstance(exporter_class) if exporter is not None: depth = self.get_depth() print "Depth: {}".format(depth) events = (thing.get_events(depth=depth) # The series is referenced from event in order to use # the series title in the output, so it helps to # prefetch the series to avoid len(events) queries # when iterating over events. .prefetch_related("source")) return exporter.export(events, feed_name=self._path_to_filename(thing.fullpath)) return HttpResponseBadRequest("Sorry, Format not recognized, can't load class %s " % exporter_class ) return HttpResponseBadRequest("Sorry, Format not recognized") except Thing.DoesNotExist: return HttpResponseNotFound()
def post(self, request, thing): user = ThingSubject(fullpath=thing) # Check if the user is logged in if request.user.is_anonymous(): return HttpResponseForbidden("Not logged in") elif not request.user.has_perm(Thing.PERM_LINK, user): return HttpResponseForbidden("Not your calendar") hashid = Thing.hash(thing) # Check if the thing exists try: thing = Thing.objects.get(pathid=hashid) except Thing.DoesNotExist: return HttpResponseNotFound() site_url = get_site_url_from_request(request) new_hmac = user.create_hmac(True) new_feed_path = reverse("export ics hmac", kwargs={ "thing": thing, "hmac": new_hmac }) return HttpResponse(site_url + new_feed_path)
def __get_thing(self): try: path = self.get_thing_fullpath() return Thing.objects.get(pathid=Thing.hash(path)) except Thing.DoesNotExist: # Raise permission denied instead of 404 when a Thing does # not exist to avoid leaking presence of a user... raise PermissionDenied
def process_module_dict(self, module): """ Processes a ModuleData dict and updates the database """ path = module['path'] try: db_module = self.thing_list.get( pathid=Thing.hash(path+module['shortname']) ) except Thing.DoesNotExist: db_module = None is_deleting_module = module.is_being_deleted() if db_module is None: if is_deleting_module: # wanted to delete it, doesn't exist, nothing to do return db_module = self.create_module( path, module['name'], module['shortname'] ) if db_module is None: # something went wrong creating the module (no need to report # it as the logger should already contain the details) return # check if we want to delete it if is_deleting_module: self.delete_module(db_module) return # create a list of child sources module_sources = [] matching_source_tags = self.event_source_list.filter( thing=db_module, annotation='home' ) for tag in matching_source_tags: # check it was imported via the api if 'importid' in tag.eventsource.metadata: module_sources.append( (tag.eventsource, tag.eventsource.metadata['importid']) ) for source in module['seriesList']: db_source = self.process_source_dict( module_sources, db_module, source ) if db_source is not None: module_sources.append( (db_source, db_source.metadata['importid']) )
def create_salt(self, update=False): ''' Create or update salt in the Thing metadata. Separated from create_hmac so that user salts may be regenerated independently. ''' t = self._get_thing() metadata = t.metadata if update or 'salt' not in metadata: metadata['salt'] = Thing.hash(now().isoformat()) t.save() return True return False
def _get_subject_perms(self, user_obj, obj): try: # Is there anything associated with the user userthing = Thing.objects.get(pathid=Thing.hash("user/%s" % user_obj.username)) if ThingTag.objects.filter(thing=userthing, annotation="admin").count() > 0: return self.ALL except Thing.DoesNotExist: pass return self.JUST_READ
def userHasAccess(user, path): # can this user admin the Thing with that full path # this is set in the users page up to the level before module path = re.sub('/$', '', path) # remove end slash try: thing = Thing.objects.get(pathid=Thing.hash(path)) except Thing.DoesNotExist: return False except Thing.MultipleObjectsReturned: return False return thing.can_be_edited_by(user.username)
def _get_subject_perms(self, user_obj, obj): try: # Get the thing associated with this user userthing = Thing.objects.get(pathid=Thing.hash("user/%s" % user_obj.username)) # Check if this eventsource is associated with an admin annotation via eventsourcetag es = obj.event_source if es is not None: EventSource.objects.get(id=es.id, eventsourcetag__thing=userthing, eventsourcetag__annotation="admin") return self.ALL except Thing.DoesNotExist: pass except EventSource.DoesNotExist: pass return self.JUST_READ
def _get_subject_perms(self, user_obj, obj): # This is a little more complex, we need to find out if the users Thing is associated with # the event. try: # Get the thing associated with this user userthing = Thing.objects.get(pathid=Thing.hash("user/%s" % user_obj.username)) # Check if this event is associated with an admin annotation via eventtag or eventsourcetag e = obj.event if e is not None: Event.objects.filter(id=e.id).get( models.Q(eventtag__thing=userthing, eventtag__annotation="admin") | models.Q(source__eventsourcetag__thing=userthing, source__eventsourcetag__annotation="admin")) return self.ALL except Thing.DoesNotExist: pass except Event.DoesNotExist: pass return self.JUST_READ
def add_module_data(self, module): """ Adds the data in module to the database. Performs a check to ensure that user has the appropriate permission. Will not create Things above the module level. """ try: module.is_valid() except DataValidationException as err: self.logger.log( 'failed', 'module', 'Module data not valid {0}'.format(err) ) return path = module['path'] # find the parent of the module try: parent_thing = self.thing_list.get(pathid=Thing.hash(path[:-1])) except Thing.DoesNotExist: self.logger.log( 'failed', 'module', 'The path {0} does not exist'.format(path[:-1]) ) return # check for permission if not parent_thing.can_be_edited_by(self.user.username): self.logger.log( 'denied', 'module', 'You do not have permission to modify {0}'.format(path[:-1]) ) return self.process_module_dict(module)
def get_uncategorised_module_for_thing(self, orm, parent_thing): fullpath = "{}/{}".format(parent_thing.fullpath, "uncategorised") pathid = RealThing.hash(fullpath) assert pathid assert "/" in fullpath assert fullpath.endswith("uncategorised") assert parent_thing.pk is not None thing, created = orm.Thing.objects.get_or_create(pathid=pathid, defaults={ "parent": parent_thing, "fullpath": fullpath, "name": "uncategorised", "fullname": "Uncategorised", "type": "module" }) return thing
def get(self, request, thing): if not request.user.has_perm(Thing.PERM_READ, ThingSubject(fullpath=thing)): return HttpResponseForbidden("Denied") hashid = Thing.hash(thing) try: thing = Thing.objects.get(pathid=hashid) typeofthing = thing.type if typeofthing is None: typeofthing = "default" context = {"thing": thing, "events": thing.get_events()} try: return render( request, "student/things/thing-events-%s.html" % typeofthing, context) except: return render(request, "student/things/thing-events-default.html", context) except Thing.DoesNotExist: return HttpResponseNotFound()
def _get_thing(self): if self._thing is None: self._thing = Thing.objects.get(pathid=Thing.hash(self.fullpath)) return self._thing
def get_user_pathid(self): user_thing_path = self.get_user_thing_path() if user_thing_path is None: return None return Thing.hash(self.get_user_thing_path())
def get_subject_pathid(self): return Thing.hash(self.kwargs["thing"])
def get(self, request, thing): if not request.user.has_perm( Thing.PERM_READ, ThingSubject(fullpath=thing, fulldepth=True)): return HttpResponseForbidden("Denied") try: thing = Thing.objects.get(pathid=Thing.hash(thing)) relatedthings = frozenset() relatedsources = frozenset() related_path = request.GET[ChildrenView.QUERY_RELATED] if related_path: # Get the things linked to the thing supplied by EventTag or EventSourceTag # eventtag__event__eventtag__thing__in looks for things linked to the same event # eventsourcetag__eventsource__eventsourcetag__thing for things linked to the same eventsource related_children_q = Thing.treequery([related_path]) related = Thing.objects.filter(related_children_q) contains_event_in_related = models.Q( eventtag__event__eventtag__thing__in=related, eventtag__event__current=True) contains_eventseries_in_related = models.Q( eventsourcetag__eventsource__eventsourcetag__thing__in= related, eventsourcetag__eventsource__current=True) relatedthings = frozenset( Thing.objects.filter( contains_event_in_related | contains_eventseries_in_related).values_list( "fullpath", flat=True)) # get all the sources that the target has related relatedsources = frozenset( EventSource.objects.filter( eventsourcetag__thing__in=related, current=True).values_list("id", flat=True)) raw_modules = Thing.objects.filter( parent__pathid=thing.pathid).prefetch_related( "eventsourcetag_set__eventsource", "thing_set__eventsourcetag_set__eventsource") modules = [] for raw_module in raw_modules: module = { "id": raw_module.id, "title": raw_module.fullname, "fullpath": raw_module.fullpath, "in_calendar": raw_module.fullpath in relatedthings } series = [] for eventsourcetag in raw_module.eventsourcetag_set.all(): raw_series = eventsourcetag.eventsource single_series = { "id": raw_series.id, "title": raw_series.title, "date_pattern": raw_series.metadata.get("datePattern", ""), "location": raw_series.metadata.get("location", ""), "people": raw_series.metadata.get("people", []), "in_calendar": raw_series.id in relatedsources } series.append(single_series) module["series"] = sorted_naturally(series, key=itemgetter("title")) modules.append(module) raw_links = ThingTag.objects.filter(annotation="link", thing=thing) links = [] for raw_link in raw_links: target = raw_link.targetthing if target.type == "part": name = target.parent.fullname + ", " + target.fullname else: name = target.fullname + " " + "(" + target.parent.parent.fullname + "), " + target.parent.fullname link = {"fullpath": target.fullpath, "name": name} links.append(link) context = { "modules": sorted_naturally(modules, key=itemgetter("title")), "links": sorted_naturally(links, key=itemgetter("name")) } return render(request, "student/modules-list/base.html", context) except Thing.DoesNotExist: return HttpResponseNotFound()
def post(self, request, thing): # Check if the user is logged in if request.user.is_anonymous(): return HttpResponseForbidden("Not logged in") elif not request.user.has_perm(Thing.PERM_LINK, ThingSubject(fullpath=thing)): return HttpResponseForbidden("Not your calendar") hashid = Thing.hash(thing) try: try: thing = Thing.objects.get(pathid=hashid) except Thing.DoesNotExist: path = "user/%s" % request.user.username if thing == path: thing = Thing.get_or_create_user_thing(request.user) # Delete associations first elist = self._expand(request.POST.getlist("esd")) if len(elist) > 0: EventSourceTag.objects.filter( thing=thing, eventsource__in=EventSource.objects.filter( id__in=elist)).delete() elist = self._expand(request.POST.getlist("ed")) if len(elist) > 0: EventTag.objects.filter( thing=thing, event__in=Event.objects.filter(id__in=elist)).delete() # If there is a list of things to delete, this is a little more complicated. tlist = self._expand(request.POST.getlist("td")) if len(tlist) > 0: # remove all EventTags and EventSourceTags that link this thing to Events or EventSource linked to by any child # The following query gets the decendents of all the things listed decendents = Thing.objects.filter(Thing.treequery(tlist)) # Then get the Events associated with all the decendents of all the things decendent_events = Event.objects.filter( eventtag__thing__in=decendents) # And delete all events tags on this thing, that match those events. EventTag.objects.filter(thing=thing, event__in=decendent_events).delete() # get all eventsources that are associated with the list of decendent things decendent_eventsource = EventSource.objects.filter( eventsourcetag__thing__in=decendents) EventSourceTag.objects.filter( thing=thing, eventsource__in=decendent_eventsource).delete() # Add associations elist = self._expand(request.POST.getlist("es")) if len(elist) > 0: # Delete then bulk add, note that no hooks on bulk add EventSourceTag.objects.filter( thing=thing, eventsource__in=EventSource.objects.filter( id__in=elist)).delete() items = [] for es in EventSource.objects.filter(id__in=elist, current=True): eventsourcetag = EventSourceTag(thing=thing, eventsource=es) eventsourcetag.on_pre_save() items.append(eventsourcetag) EventSourceTag.objects.bulk_create(items) elist = self._expand(request.POST.getlist("e")) if len(elist) > 0: # Delete then bulk add, note that no hooks on bulk add EventTag.objects.filter( thing=thing, event__in=Event.objects.filter(id__in=elist)).delete() items = [] for e in Event.objects.filter(id__id=elist, current=True): eventtag = EventTag(thing=thing, event=e) eventtag.on_pre_save() items.append(eventtag) EventTag.objects.bulk_create(items) tlist = self._expand(request.POST.getlist("t")) if len(tlist) > 0: # remove all EventTags and EventSourceTags that link this thing to Events or EventSource linked to by any child # The following query gets the decendents of all the things listed decendents = Thing.objects.filter(Thing.treequery(tlist)) # Then get the Events associated with all the decendents of all the things decendent_events = Event.objects.filter( eventtag__thing__in=decendents) # And delete all events tags on this thing, that match those events. EventTag.objects.filter(thing=thing, event__in=decendent_events).delete() # get all eventsources that are associated with the list of decendent things decendent_eventsource = EventSource.objects.filter( eventsourcetag__thing__in=decendents) EventSourceTag.objects.filter( thing=thing, eventsource__in=decendent_eventsource).delete() # Having deleted, we need to add, first the events bulk creating EventTags items = [] for e in decendent_events.filter(current=True): eventtag = EventTag(thing=thing, event=e) eventtag.on_pre_save() items.append(eventtag) EventTag.objects.bulk_create(items) # Next the Event Sources bulk creating EventSourceTags items = [] for es in decendent_eventsource.filter(current=True): eventtag = EventSourceTag(thing=thing, eventsource=es) eventtag.on_pre_save() items.append(eventtag) EventSourceTag.objects.bulk_create(items) return HttpResponse("ok") except Thing.DoesNotExist: return HttpResponseNotFound()