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(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()