Ejemplo n.º 1
0
def page_get(userauth, prjname):
    pmd = config.cache.get_pmd(prjname)
    if pmd is None:
        abort(404, "Project does not exist")
        return

    pdata = pmd.pdata
    if pdata.projtype.has_grflangid:
        return template('upload_lang', userauth=userauth, pmd=pmd)
    else:
        return template('upload_lang_select',
                        userauth=userauth,
                        pmd=pmd,
                        lnginfos=sorted(pdata.get_all_languages(),
                                        lambda l: l.isocode))
Ejemplo n.º 2
0
def language(userauth, lngname):
    """
    Get an overview of the state of the given language in every project.

    @param lngname: Name of the language (isocode).
    @type  lngname: C{str}
    """

    lnginfo = language_info.isocode.get(lngname)
    if lnginfo is None:
        abort(404, "Language is unknown")
        return

    prjdata = []
    for pmd in config.cache.projects.values():
        lstate = pmd.overview.get(lngname)
        if lstate is not None:
            prjdata.append((pmd, True, lstate))
        else:
            lstate = [0 for i in range(data.MAX_STATE)]
            lstate[data.MISSING] = pmd.blang_count
            prjdata.append((pmd, False, lstate))

    prjdata.sort(key=lambda p: p[0].human_name.lower())
    return template('language',
                    userauth=userauth,
                    lnginfo=lnginfo,
                    prjdata=prjdata)
Ejemplo n.º 3
0
def page_post(userauth):
    prjname = request.forms.name.lower().strip()
    acceptance = utils.verify_name(prjname, "Project identifier", True)
    if acceptance is not None:
        redirect('/newproject', message=acceptance)
        return

    if prjname in config.cache.projects:
        redirect('/newproject',
                 message="Project \"{}\" already exists".format(prjname))
        return

    ptype_name = request.forms.projtype_select
    projtype = None
    for prjtp in project_type.project_types.values():
        if prjtp.human_name == ptype_name and prjtp.name in config.cfg.project_types:
            projtype = prjtp
            break
    if projtype is None:
        redirect('/newproject', message='No known project type provided')
        return
    return template('createproject_form',
                    userauth=userauth,
                    projtype_name=projtype.name,
                    prjname=prjname)
Ejemplo n.º 4
0
def page_get(userauth):
    all_ptype_names = []
    for projtype in project_type.project_types.values():
        if projtype.name in config.cfg.project_types:
            all_ptype_names.append(projtype.human_name)
    all_ptype_names.sort()
    return template("newproject_form", userauth=userauth, all_ptype_names=all_ptype_names)
Ejemplo n.º 5
0
def userprofile(userauth):
    """
    Get an overview of the (write) access rights of a user in every project.
    """
    prjdata = []
    languages = {}
    is_owner = False
    for pmd in config.cache.projects.values():
        owner = userauth.may_read("projsettings", pmd.name, "-")
        is_owner |= owner
        langs = {}
        for lang in language_info.all_languages:
            lngname = lang.isocode
            lstate = pmd.overview.get(lngname)
            exist = False
            translator = False
            if lstate is not None:
                exist = True
                translator = userauth.may_read("string", pmd.name, lngname)
            else:
                lstate = [ 0 for i in range(data.MAX_STATE) ]
                lstate[data.MISSING] = pmd.blang_count
                translator = userauth.may_read("makelanguage", pmd.name, lngname)

            langs[lngname] = (exist, lstate, translator)

            if translator and not owner:
                # Collect languages with translator access, but do not spam language list due to owner access
                languages[lngname] = lang

        prjdata.append((pmd, owner, langs))

    prjdata.sort(key = lambda p: p[0].human_name.lower())
    return template('userprofile', userauth = userauth, prjdata = prjdata, is_owner = is_owner, lnginfos = sorted(languages.values(), key=lambda x:x.isocode))
Ejemplo n.º 6
0
def new_language_get(userauth, prjname):
    """
    Form to add another language to the project.
    """
    pmd = config.cache.get_pmd(prjname)
    if pmd is None:
        abort(404, "Project does not exist")
        return

    pdata = pmd.pdata

    base_langs = []
    translations = []
    can_be_added = []
    for lang in pdata.get_all_languages():
        if lang.isocode == pdata.base_language:
            base_langs.append(lang)
            continue
        if lang.isocode in pdata.languages:
            translations.append(lang)
            continue
        can_be_added.append(lang)

    translations.sort(key=lambda x: x.isocode)
    can_be_added.sort(key=lambda x: x.isocode)

    return template(
        "newlanguage",
        userauth=userauth,
        pmd=pmd,
        base_langs=base_langs,
        translations=translations,
        can_be_added=can_be_added,
    )
Ejemplo n.º 7
0
def project(userauth, prjname):
    pmd = config.cache.get_pmd(prjname)
    if pmd is None:
        abort(404, "Project does not exist")
        return

    pdata = pmd.pdata
    base_lng = pdata.get_base_language()
    transl = []
    bcounts = None
    if base_lng is not None:
        for lname, lng in pdata.languages.items():
            if lng is base_lng: continue
            transl.append((lng, pmd.overview.get(lname)))

        transl.sort(key=lambda x: x[0].name)

        bcounts = pmd.overview.get(base_lng.name)

    return template('project',
                    userauth=userauth,
                    pmd=pmd,
                    transl=transl,
                    base_lng=base_lng,
                    bcounts=bcounts)
Ejemplo n.º 8
0
def project_get(userauth, prjname):
    pmd = config.cache.get_pmd(prjname)
    if pmd is None:
        abort(404, "Project does not exist")
        return

    return template("projsettings", userauth=userauth, pmd=pmd)
Ejemplo n.º 9
0
def project(userauth, prjname, lngname):
    pmd = config.cache.get_pmd(prjname)
    if pmd is None:
        abort(404, "Project does not exist")
        return

    pdata = pmd.pdata
    lng = pdata.languages.get(lngname)
    if lng is None:
        abort(404, "Language does not exist in the project")
        return
    assert pdata.projtype.allow_case or lng.case == [""]

    blng = pdata.get_base_language(
    )  # As above we established there is at least one language, this should work.
    stored = [[] for i in range(data.MAX_STATE)]
    sdict = pdata.statistics
    sdict = sdict.get(lngname)  # Statistics dict for the queried language.
    if sdict is None:
        abort(404, "Missing language statistics")
        return

    for sname, bchgs in blng.changes.items():
        cstates = sdict[sname]
        state = max(s[1] for s in cstates)
        if state != data.MISSING_OK:
            bchg = data.get_newest_change(bchgs, "")
            sdd = StringDisplayData(sname, bchg.base_text)
            chgs = lng.changes.get(sname)
            if chgs is not None:
                cases = data.get_all_newest_changes(chgs, lng.case)
                for case, cstate in cstates:
                    chg = cases[case]
                    if chg is not None:
                        if lng is blng:
                            text = chg.base_text.text
                        else:
                            text = chg.new_text.text
                            if text == "" and case != "":
                                # Suppress empty non-default case from translations.
                                continue
                        cdd = CaseDisplayData(case,
                                              data.STATE_MAP[cstate].name,
                                              text)
                        sdd.cases.append(cdd)

            stored[state].append(sdd)

    for strs in stored:
        strs.sort()
    return template("translation",
                    userauth=userauth,
                    pmd=pmd,
                    is_blng=(lng == blng),
                    lng=lng,
                    stored=stored)
Ejemplo n.º 10
0
def page_get_subdir(userauth, prjname, lngname):
    pmd = config.cache.get_pmd(prjname)
    if pmd is None:
        abort(404, "Project does not exist")
        return

    linfo = language_info.isocode.get(lngname)
    if linfo is None:
        abort(404, "Language is unknown")
        return
    return template("upload_lang_subdir",
                    userauth=userauth,
                    pmd=pmd,
                    lnginfo=linfo)
Ejemplo n.º 11
0
def login(userauth):
    req_redirect = request.query.get("redirect")
    req_login = request.query.get("login")

    if userauth.is_auth:
        login_success(req_redirect)
    elif users.oauth_redirect:
        session, url = users.oauth_redirect(req_redirect, req_login)
        start_session(session)
        redirect(url)
    elif users.get_authentication:
        return utils.template("login", userauth=userauth, req_login=req_login, req_redirect=req_redirect)
    else:
        abort(500, "No authentication method")
        return
Ejemplo n.º 12
0
def new_language_post(userauth, prjname):
    """
    Construct the requested language.
    """
    pmd = config.cache.get_pmd(prjname)
    if pmd is None:
        abort(404, "Project does not exist")
        return

    new_iso = request.forms.language_select

    lng_def = get_language(new_iso)
    if lng_def is None:
        msg = "No language found that can be created"
        abort(404, msg)
        return

    return template("makelanguage",
                    userauth=userauth,
                    pmd=pmd,
                    lnginfo=lng_def)
Ejemplo n.º 13
0
def login(userauth):
    if not users.get_authentication:
        abort(500, "No authentication method")
        return

    req_redirect = request.forms.get("redirect")
    req_login = request.forms.get('login')
    req_password = request.forms.get('password')

    if req_login and req_password:
        userauth = users.get_authentication(req_login, req_password)
        if userauth.is_auth:
            start_session(userauth)
            login_success(req_redirect)
            return

    return utils.template('login',
                          userauth=userauth,
                          req_login=req_login,
                          req_redirect=req_redirect,
                          message='Try harder!',
                          message_class='error')
Ejemplo n.º 14
0
def delete_form(userauth, prjname, lngname):
    pmd = config.cache.get_pmd(prjname)
    if pmd is None:
        abort(404, "Project does not exist")
        return

    if pmd.storage_type == config.STORAGE_SEPARATE_LANGUAGES:
        abort(
            404,
            "Cannot delete a language, ask the system administrator to remove the language file"
        )
        return

    pdata = pmd.pdata
    lng = pdata.languages.get(lngname)
    if lng is None:
        abort(404, "Language does not exist in the project")
        return

    if pdata.base_language == lngname:
        abort(404, "Cannot delete base language!")
        return

    return template("delete_translation", userauth=userauth, pmd=pmd, lng=lng)
Ejemplo n.º 15
0
def login_post(userauth):
    if not users.get_authentication:
        abort(500, "No authentication method")
        return

    req_redirect = request.forms.get("redirect")
    req_login = request.forms.get("login")
    req_password = request.forms.get("password")

    if req_login and req_password:
        userauth = users.get_authentication(req_login, req_password)
        if userauth.is_auth:
            start_session(userauth)
            login_success(req_redirect)
            return

    return utils.template(
        "login",
        userauth=userauth,
        req_login=req_login,
        req_redirect=req_redirect,
        message="Try harder!",
        message_class="error",
    )
Ejemplo n.º 16
0
def handle_upload(userauth, pmd, projname, langfile, override, is_base,
                  lng_data):
    """
    Process the upload.

    @param userauth: User authentication.
    @type  userauth: L{UserAuthentication}

    @param pmd: Project meta data.
    @type  pmd: L{ProjectMetaData}

    @param projname: Project name.
    @type  projname: C{str}

    @param langfile: Language file to load if available.
    @type  langfile: C{file} or C{None}

    @param override: Override existing text.
    @type  override: C{bool}

    @param lng_data: Used language, if provided.
    @type  lng_data: L{LanguageData} or C{None}
    """
    pdata = pmd.pdata

    # Missing language file in the upload.
    if not langfile or not langfile.file:
        abort(404, "Missing language file")
        return

    base_language = pdata.get_base_language()

    # Cannot download a translation without base language.
    if not is_base and base_language is None:
        abort(404, "Project has no base language")
        return

    # Parse language file, and report any errors.
    ng_data = language_file.load_language_file(pdata.projtype, langfile.file,
                                               config.cfg.language_file_size,
                                               lng_data)
    if len(ng_data.errors) > 0:
        return template('upload_errors',
                        userauth=userauth,
                        pmd=pmd,
                        errors=ng_data.errors)

    # Is the language allowed?
    if not pdata.projtype.allow_language(ng_data.language_data):
        abort(
            404, "Language \"{}\" may not be uploaded".format(
                ng_data.language_data.isocode))
        return

    stamp = data.make_stamp()

    lng = pdata.languages.get(ng_data.language_data.isocode)
    if lng is None:  # New language being added.
        result = add_new_language(ng_data, pdata, is_base)
        if not result[0]:
            abort(404, result[0])
            return
        lng = result[1]
        if is_base and base_language is None: base_language = lng

    if is_base:
        if base_language is not None and base_language != lng:
            abort(404, "Cannot change a translation to a base language")
            return

        # Add strings as changes.
        for sv in ng_data.strings:
            sv.text = language_file.sanitize_text(sv.text)
            chgs = base_language.changes.get(sv.name)
            chg = get_blng_change(sv, base_language)
            if chg is None:  # New change.
                base_text = data.Text(sv.text, sv.case, stamp)
                chg = data.Change(sv.name, sv.case, base_text, None, stamp,
                                  userauth.name, True)
                if chgs is None:
                    chgs = [chg]
                    base_language.changes[sv.name] = chgs
                else:
                    chgs.append(chg)
            else:
                # Only way to update a base language is by upload, no need for override check.
                chg.stamp = stamp
                chg.user = userauth.name

            for c in chgs:
                c.last_upload = (c == chg)

        # Update language properties as well.
        copy_lng_properties(pdata.projtype, ng_data, base_language)

        pdata.skeleton = ng_data.skeleton  # Use the new skeleton file.
        pdata.flush_related_cache()  # Drop the related strings cache.
        pdata.set_modified()

        # Push the new set of string-names to all languages (this includes the base language).
        str_names = set(sv.name for sv in ng_data.strings)
        for lang in pdata.languages.values():
            lng_modified = False
            not_seen = str_names.copy()
            for sn in list(lang.changes.keys()):
                not_seen.discard(sn)
                if sn in str_names: continue  # Name is kept.
                del lang.changes[sn]  # Old string, delete
                lng_modified = True
            for sn in not_seen:
                # Missing translation are not saved, so no set_modified here.
                lang.changes[sn] = []

            if lng_modified:
                lang.set_modified()

    else:
        # Not a base language -> it is a translation.
        if base_language is not None and base_language == lng:
            abort(404, "Cannot change a base language to a translation")
            return

        for sv in ng_data.strings:
            sv.text = language_file.sanitize_text(sv.text)

            # Find base language string for 'sv'.
            bchgs = base_language.changes.get(sv.name)
            if bchgs is None:
                continue  # Translation has a string not in the base language
            bchg = data.get_newest_change(bchgs, '')
            if bchg is None: continue  # Nothing to base against.
            base_text = bchg.base_text

            chgs = lng.changes.get(sv.name)
            chg = get_lng_change(sv, lng, base_text)
            if chg is None:  # It's a new text or new case.
                lng_text = data.Text(sv.text, sv.case, stamp)
                chg = data.Change(sv.name, sv.case, base_text, lng_text, stamp,
                                  userauth.name, True)
                if chgs is None:
                    lng.changes[sv.name] = [chg]
                else:
                    for c in chgs:
                        c.last_upload = False
                    chgs.append(chg)
            elif override:  # Override existing entry.
                chg.stamp = stamp
                chg.user = userauth.name
                for c in chgs:
                    c.last_upload = (c == chg)

        # Update language properties as well.
        copy_lng_properties(pdata.projtype, ng_data, lng)
        lng.set_modified()

    config.cache.save_pmd(pmd)

    if is_base:
        pmd.create_statistics(None)  # Update all languages.
    else:
        pmd.create_statistics(lng)

    message = "Successfully uploaded language '" + lng.name + "' " + utils.get_datetime_now_formatted(
    )
    redirect("/project/<prjname>", prjname=projname, message=message)
Ejemplo n.º 17
0
def root(userauth):
    return template("root", userauth=userauth)
Ejemplo n.º 18
0
def root(userauth):
    # projs: C{list} of L{ProjectMetaData}
    projs = sorted(config.cache.projects.values(),
                   key=lambda p: p.human_name.lower())
    return template("projects", userauth=userauth, projects=projs)
Ejemplo n.º 19
0
def output_string_edit_page(userauth,
                            bchg,
                            binfo,
                            lng,
                            pmd,
                            lngname,
                            sname,
                            states=None,
                            messages=[]):
    """
    Construct a page for editing a string.

    @param bchg: Last version of the base language.
    @type  bchg: L{Change}

    @param binfo: Information about the state of the L{bchg} string.
    @type  binfo: L{StringInfo}

    @param lng: Language being translated.
    @type  lng: L{Language}

    @param pmd: Project Meta Data.
    @type  pmd: L{ProjectMetaData}

    @param lngname: Language name.
    @type  lngname: C{str}


    @param sname: Name of the string.
    @type  sname: C{str}

    @param states: Changes, state and errors for (some of) the cases, omission of a case
                   means the function should derive it from the language.
    @type  states: C{dict} of C{str} to tuple (L{Change}, C{int}, C{list} of L{ErrorMessage}),
                   use C{None} to derive all.

    @return: Either an error, or an instantiated template.
    @rtype:  C{None} or C{str}
    """
    if states is None:
        states = {}
    pdata = pmd.pdata
    projtype = pdata.projtype

    # Mapping of case to list of related strings.
    related_cases = dict((case, []) for case in lng.case)
    for rel_sname in pdata.get_related_strings(sname):
        rel_chgs = lng.changes.get(rel_sname)
        if rel_chgs is not None:
            rel_chgs = data.get_all_newest_changes(rel_chgs, lng.case)
            for case, chg in rel_chgs.items():
                if chg is not None and chg.new_text is not None:
                    rc = related_cases.get(case)
                    if rc is not None:
                        rc.append(RelatedString(rel_sname, chg.new_text))

    case_chgs = data.get_all_changes(lng.changes.get(sname), lng.case, None)
    now = data.make_stamp()

    transl_cases = []
    for case in lng.case:
        tranls = []

        cchgs = [(cchg, True) for cchg in case_chgs[case]
                 ]  # Tuples (case-change, 'saved translation')
        chg_err_state = states.get(case)
        if chg_err_state is not None:
            cchgs.append((chg_err_state[0], False))
        if len(cchgs) == 0:
            # No changes for this case, make a dummy one to display the base data.
            tra = Translation(bchg, None, now, False)
            if case == "":
                tra.errors = [
                    language_file.ErrorMessage(language_file.ERROR, None,
                                               "String is missing")
                ]
                tra.state = data.STATE_MAP[data.MISSING].name
            else:
                tra.errors = []
                tra.state = data.STATE_MAP[data.MISSING_OK].name

            tranls.append(tra)

        else:
            # Changes do exist, add them (in reverse chronological order).
            cchgs.reverse()
            for idx, (lchg, saved) in enumerate(cchgs):
                tra = Translation(bchg, lchg, now, saved)
                if idx == 0:
                    # Newest string, add errors
                    if chg_err_state is not None:
                        state, errors = chg_err_state[1], chg_err_state[2]
                    else:
                        state, errors = data.get_string_status(
                            projtype, lchg, case, lng, bchg.base_text, binfo)

                    tra.errors = errors
                    tra.state = data.STATE_MAP[state].name
                else:
                    # For older translations, the errors and state are never displayed.
                    tra.errors = []
                    tra.state = data.STATE_MAP[data.MISSING_OK].name

                tranls.append(tra)

        if projtype.allow_case or case == "":
            transl_cases.append(
                TransLationCase(case, tranls, related_cases[case]))

    related_languages = []
    if lng.name[:3] != pdata.base_language[:3]:
        for n, l in pdata.languages.items():
            if n[:3] != lng.name[:3] or n == lng.name:
                continue

            related = data.get_newest_change(lng.changes.get(sname), "")
            if related is not None:
                related_languages.append((l, related))
    related_languages.sort(key=lambda x: x[0].name)

    return template(
        "string_form",
        userauth=userauth,
        pmd=pmd,
        lng=lng,
        sname=sname,
        plurals=language_info.all_plurals[lng.plural].description,
        genders=lng.gender,
        cases=lng.case,
        related_languages=related_languages,
        tcs=transl_cases,
        messages=messages,
    )


@route("/string/<prjname>/<lngname>/<sname>", method="GET")
@protected(["string", "prjname", "lngname"])
def str_form(userauth, prjname, lngname, sname):
    parms = check_page_parameters(prjname, lngname, sname)
    if parms is None:
        return

    pmd, bchg, lng, binfo = parms
    return output_string_edit_page(userauth, bchg, binfo, lng, pmd, lngname,
                                   sname, None)


@route("/string/<prjname>/<lngname>/<sname>", method="POST")
@protected(["string", "prjname", "lngname"])
def str_post(userauth, prjname, lngname, sname):
    parms = check_page_parameters(prjname, lngname, sname)
    if parms is None:
        return

    pmd, bchg, lng, binfo = parms

    request.forms.recode_unicode = False  # Allow Unicode input
    request_forms = request.forms.decode()  # Convert dict to Unicode.

    base_str = request_forms.get(
        "base")  # Base text translated against in the form.
    if base_str is None or base_str != bchg.base_text.text:
        abort(
            404,
            "Base language has been changed, please translate the newer version instead"
        )
        return

    # Get changes against bchg
    case_chgs = data.get_all_changes(lng.changes.get(sname), lng.case, bchg)
    projtype = pmd.pdata.projtype

    stamp = None  # Assigned a stamp object when a change is made in the translation.

    # Collected output data
    new_changes = []
    new_state_errors = {}

    for case in lng.case:
        trl_str = request_forms.get("text_" +
                                    case)  # Translation text in the form.
        if trl_str is None:
            continue  # It's missing from the form data.

        trl_str = language_file.sanitize_text(trl_str)
        if case == "" and trl_str == "" and bchg.base_text != "":
            # Empty base case for a non-empty string, was the "allow empty base translation" flag set?
            if request_forms.get("allow_empty_default") != "on":
                if stamp is None:
                    stamp = data.make_stamp()
                txt = data.Text(trl_str, case, stamp)
                tchg = data.Change(sname, case, bchg.base_text, txt, stamp,
                                   userauth.name)
                error = language_file.ErrorMessage(
                    language_file.ERROR,
                    None,
                    "Empty default case is not allowed (enable by setting 'Allow empty input').",
                )
                new_state_errors[case] = (tchg, data.INVALID, [error])
                continue

        # Check whether there is a match with a change in the translation.
        trl_chg = None
        for cchg in case_chgs[case]:
            if cchg.new_text.text == trl_str:
                trl_chg = cchg
                break

        if trl_chg is None:
            if case != "" and trl_str == "" and len(case_chgs[case]) == 0:
                continue  # Skip adding empty non-base cases if there are no strings.

            # A new translation against bchg!
            if stamp is None:
                stamp = data.make_stamp()
            txt = data.Text(trl_str, case, stamp)
            tchg = data.Change(sname, case, bchg.base_text, txt, stamp,
                               userauth.name)
            state, errors = data.get_string_status(projtype, tchg, case, lng,
                                                   bchg.base_text, binfo)
            if state == data.MISSING or state == data.INVALID:
                new_state_errors[case] = (tchg, state, errors)
            else:
                new_changes.append(tchg)

            continue
Ejemplo n.º 20
0
def languages(userauth):
    """
    Get an overview of used languages over all projects.
    """
    languages = sorted(language_info.all_languages, key=lambda l: l.isocode)
    return template('languages', userauth=userauth, lnginfos=languages)
Ejemplo n.º 21
0
def root(userauth):
    return template('root', userauth=userauth)