Beispiel #1
0
    def PATCH(self):
        req = cherrypy.request
        versions = library.versions

        for url, attrs in libraries.normalize(req.json["index"]).iteritems():
            name = url.split("/")[-2]

            if (
                    # Anyone can add a version (with themselves as admin)...
                (name not in versions.auth) or
                    # but only admins can change permissions...
                    versions.permit(name, req.login, 'admin')):
                auth = attrs.get("auth", {})
                to_version = versions[name]

                if name not in versions.version_names:
                    versions.version_names.append(name)
                    to_version.save_works()

                # ...but they cannot remove themself as an admin.
                auth.setdefault("permissions", {})[req.login] = "admin"
                auth.setdefault("locked", False)
                versions.auth[name] = auth

                if "notes" in attrs:
                    v = versions[name]
                    if v.version_notes != attrs["notes"]:
                        v.version_notes = attrs["notes"]
                        v.save_version_notes()

        library.save_auth()
        cherrypy.response.status = 204
Beispiel #2
0
    def PATCH(self):
        version = auth_version('writer')
        req = cherrypy.request

        new_works = libraries.normalize(req.json["index"])
        # TODO: validation
        for workurl, work in new_works.iteritems():
            workid = workurl.split("/")[-2]
            if work is None:
                version.destroy_work(workid)
            else:
                if workid in version.works:
                    if "name" in work:
                        version.works[workid]["name"] = work["name"]
                else:
                    version.works[workid] = {
                        "name": work.get("name", workid),
                        "sections": []
                    }
                    version.worksorder.append(workid)
                existing_sections = version.works[workid]["sections"]

                for sectionid in set(
                        work["sections"]) - set(existing_sections):
                    # Make new (empty) sections
                    s = libraries.Section(version.name, workid, sectionid)
                    version.save_section(s)

        version.save_works()
        cherrypy.response.status = 204
Beispiel #3
0
    def GET(self, strict=False, versions=None, context=6):
        req = cherrypy.serving.request

        versions = [v for v in (versions or "").split(",") if v]
        try:
            context = int(context)
        except (TypeError, ValueError):
            context = 6

        try:
            criteria = libraries.normalize(
                libraries.simplejson.loads(req.criteria))
        except libraries.simplejson.JSONDecodeError:
            raise cherrypy.HTTPError(
                404, "Concordance criteria MUST be valid JSON")

        entries, passages, complete = library.concordance(
            versions, criteria, req.version, bool(strict), context)

        lexical_notes = {}
        for v in versions:
            version = auth_version(version=v)
            lemmas = set(entry['lemma'] for entry in entries[v].itervalues())
            lexical_notes[v] = dict(
                (lemma, version.lexical_notes[lemma])
                for lemma in lemmas.intersection(version.lexical_notes))

        response = {
            "self": url(qs=cherrypy.request.query_string),
            "element": "shoji:entity",
            "body": {
                "passages": passages,
                # These are both {version: {lemma: ...}} trees.
                "entries": entries,
                "lexical_notes": lexical_notes,
                "complete": complete
            }
        }

        # Collect parents and children.
        # This was migrated from the old lexicon view, which only ever
        # showed one lemma or wordform.
        # TODO: expand to show multiple trees, or move it to somewhere
        # in the API/UI that is more appropriate.
        # Eventually, the concept of "family" should be in the lexicon instead.
        if not isinstance(criteria, list):
            criteria = [criteria]

        lemmas = set([
            wf["lemma"] for wf in criteria if isinstance(wf, dict)
            and "lemma" in wf and isinstance(wf["lemma"], basestring)
        ])
        if len(lemmas) == 1:
            response["body"]["family"] = library.family(lemmas.pop())

        return response
Beispiel #4
0
    def PATCH(self):
        """Apply the given catalog patch document."""
        req = cherrypy.serving.request
        version = auth_version('writer')
        try:
            section = version.load_section(req.workid, req.sectionid)
        except FileNotFound:
            raise cherrypy.NotFound()

        section.update(libraries.normalize(req.json["index"]))
        version.save_section(section)

        cherrypy.response.status = 204
Beispiel #5
0
    def PATCH(self):
        """Apply the given {ids, text, lexicon} patch document."""
        req = cherrypy.serving.request
        version = auth_version('writer')

        # Bucket the words so we can load each affected section in order.
        # and also to fail the whole operation if any section cannot be found.
        index = libraries.normalize(req.json['index'])

        by_section = {}
        for id, entry in index.iteritems():
            workid, sectionid, phraseid = id.split("/", 3)
            by_section.setdefault((workid, sectionid), {})[phraseid] = entry

        for (workid, sectionid), patches in by_section.iteritems():
            section = version.load_section(workid, sectionid)
            section.update(patches)
            version.save_section(section)

        cherrypy.response.status = 204
Beispiel #6
0
    def POST(self):
        """Accept the given text, tokenize it, and append as new words."""
        req = cherrypy.serving.request
        version = auth_version('writer')

        proposed_text = libraries.normalize(req.json["body"]["text"])
        proposed_text = [
            t.strip()
            for t in re.split(r'(\W+)', proposed_text, flags=re.UNICODE)
            if t.strip()
        ]

        # Look up any existing section.
        try:
            section = version.load_section(req.workid, req.sectionid)
        except FileNotFound:
            section = libraries.Section(req.version, req.workid, req.sectionid)

        # Apply morphology as best we can.
        # Grab a map from original -> most common morphology
        # from the given other work
        lexv = req.json["body"].get("lexicon", None)
        if lexv is None:
            lexv = version
        else:
            lexv = library.versions[lexv]
        morph_map = lexv.morphology_map()

        # Assume an id scheme of work/section/x.y, where we increment 'x' by 1
        # for this set of text as a whole, and assign each word a 'y'
        # from 1 to len(text).
        verses = [id.split(".", 1)[0] for id in section.order]
        x = max([int(v) for v in verses if v.isdigit()] or [0]) + 1
        y = 0

        with section.lock:
            for word in proposed_text:
                y += 1

                verse_number = word.strip(string.punctuation)
                if verse_number.isdigit():
                    # Interpret this as a verse marker. Unfortunately, this means
                    # that text like "he bought 5 jars" may be marked incorrectly.
                    # To combat that, we only change x if it is incrementing.
                    verse_number = int(verse_number)
                    if verse_number == x + 1 or (x == verse_number == 1
                                                 and not section.order):
                        x = verse_number
                        y = 0
                        continue

                phraseid = "%s.%s" % (x, y)
                section.order.append("%s:0" % phraseid)
                section.entries[phraseid] = {
                    "parsing": "---------",
                    "lemma": "",
                    "original": word,
                    "text": [word]
                }

                match = morph_map.get(word, None)
                if match:
                    section.entries[phraseid].update(match)

            section.indices = section.calc_indices()
            version.save_section(section)

        cherrypy.response.status = 204