Example #1
0
    def _get_next_goal_count(self):
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        goal = Goal.get_most_important_incomplete_for_path(self.directory)

        if goal is not None:
            return goal.get_incomplete_words_in_path(self.directory)

        return 0
Example #2
0
    def get_next_goal_count(self):
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        goal = Goal.get_most_important_incomplete_for_path(self.directory)

        if goal is not None:
            return goal.get_incomplete_words_in_path(self.directory)

        return 0
Example #3
0
    def get_next_goal_url(self):
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        goal = Goal.get_most_important_incomplete_for_path(self.directory)

        if goal is not None:
            return goal.get_translate_url_for_path(self.directory.pootle_path,
                                                   state='incomplete')

        return ''
Example #4
0
    def get_next_goal_url(self):
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        goal = Goal.get_most_important_incomplete_for_path(self.directory)

        if goal is not None:
            return goal.get_translate_url_for_path(self.directory.pootle_path,
                                                   state='incomplete')

        return ''
Example #5
0
    def get_next_goal_url(self):
        # Trigger only if it is a regular directory inside a TP.
        if self.pootle_path.count('/') > 3:
            # Putting the next import at the top of the file causes circular
            # import issues.
            from pootle_tagging.models import Goal

            goal = Goal.get_most_important_incomplete_for_path(self)

            if goal is not None:
                return goal.get_translate_url_for_path(self.pootle_path,
                                                       state='incomplete')
        return ''
Example #6
0
    def get_next_goal_url(self):
        # Trigger only if it is a regular directory inside a TP.
        if self.pootle_path.count('/') > 3:
            # Putting the next import at the top of the file causes circular
            # import issues.
            from pootle_tagging.models import Goal

            goal = Goal.get_most_important_incomplete_for_path(self)

            if goal is not None:
                return goal.get_translate_url_for_path(self.pootle_path,
                                                       state='incomplete')
        return ''
Example #7
0
def get_translate_actions(path_obj):
    """Return a list of translation action links to be displayed for each ``path_obj``."""
    goals_summary = []

    # Build URL for getting more summary information for the current path.
    url_path_summary_more = reverse('pootle-xhr-summary-more')

    if path_obj.is_dir:
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        pootle_path = path_obj.pootle_path
        goal = Goal.get_most_important_incomplete_for_path(path_obj)

        if goal is not None:
            goal_words = goal.get_incomplete_words_in_path(path_obj)
            goal_url = goal.get_translate_url_for_path(pootle_path,
                                                       state='incomplete')
            if goal_words > 0:
                goals_summary.extend([
                    u'<br /><a class="continue-translation" href="%(url)s">' % {
                            'url': goal_url,
                        },
                    ungettext(u'<span class="caption">Next most important '
                              u'goal:</span> <span class="counter">%(num)d '
                              u'word left</span>',
                              u'<span class="caption">Next most important '
                              u'goal:</span> <span class="counter">%(num)d '
                              u'words left</span>',
                              goal_words,
                              {'num': goal_words, }),
                ])

    return {'is_dir': path_obj.is_dir,
            'goals_summary': u''.join(goals_summary),
            'summary_more_url': url_path_summary_more,
            'translate_url': path_obj.get_translate_url(state='all'),
            'incomplete_url': path_obj.get_translate_url(state='incomplete'),
            'suggestions_url': path_obj.get_translate_url(state='suggestions'),
            'critical_url': path_obj.get_critical_url(),
    }
Example #8
0
def get_translate_actions(path_obj):
    """Return a list of translation action links to be displayed for each ``path_obj``."""
    goals_summary = []

    if path_obj.is_dir:
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        pootle_path = path_obj.pootle_path
        goal = Goal.get_most_important_incomplete_for_path(path_obj)

        if goal is not None:
            goal_words = goal.get_incomplete_words_in_path(path_obj)
            goal_url = goal.get_translate_url_for_path(pootle_path,
                                                       state='incomplete')
            if goal_words > 0:
                goals_summary.extend([
                    u'<br /><a class="continue-translation" href="%(url)s">' %
                    {
                        'url': goal_url,
                    },
                    ungettext(
                        u'<span class="caption">Next most important '
                        u'goal:</span> <span class="counter">%(num)d '
                        u'word left</span>',
                        u'<span class="caption">Next most important '
                        u'goal:</span> <span class="counter">%(num)d '
                        u'words left</span>', goal_words, {
                            'num': goal_words,
                        }),
                ])

    return {
        'is_dir': path_obj.is_dir,
        'goals_summary': u''.join(goals_summary),
        'translate_url': path_obj.get_translate_url(state='all'),
        'incomplete_url': path_obj.get_translate_url(state='incomplete'),
        'suggestions_url': path_obj.get_translate_url(state='suggestions'),
        'critical_url': path_obj.get_critical_url(),
    }
Example #9
0
def get_translate_actions(path_obj):
    """Return a list of translation action links to be displayed for each ``path_obj``."""
    goals_summary = []

    if path_obj.is_dir:
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        pootle_path = path_obj.pootle_path
        goal = Goal.get_most_important_incomplete_for_path(path_obj)

        if goal is not None:
            goal_words = goal.get_incomplete_words_in_path(path_obj)
            goal_url = goal.get_translate_url_for_path(pootle_path, state="incomplete")
            if goal_words > 0:
                goals_summary.extend(
                    [
                        u'<br /><a class="continue-translation" href="%(url)s">' % {"url": goal_url},
                        ungettext(
                            u'<span class="caption">Next most important '
                            u'goal:</span> <span class="counter">%(num)d '
                            u"word left</span>",
                            u'<span class="caption">Next most important '
                            u'goal:</span> <span class="counter">%(num)d '
                            u"words left</span>",
                            goal_words,
                            {"num": goal_words},
                        ),
                    ]
                )

    return {
        "is_dir": path_obj.is_dir,
        "goals_summary": u"".join(goals_summary),
        "translate_url": path_obj.get_translate_url(state="all"),
        "incomplete_url": path_obj.get_translate_url(state="incomplete"),
        "suggestions_url": path_obj.get_translate_url(state="suggestions"),
        "critical_url": path_obj.get_critical_url(),
    }
Example #10
0
def get_path_summary(path_obj):
    """Return a list of sentences to be displayed for each ``path_obj``."""
    goals_summary = []

    # Build URL for getting more summary information for the current path.
    url_path_summary_more = reverse('pootle-xhr-summary-more')

    if path_obj.is_dir:
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        pootle_path = path_obj.pootle_path
        goal = Goal.get_most_important_incomplete_for_path(path_obj)

        if goal is not None:
            goal_words = goal.get_incomplete_words_in_path(path_obj)
            goal_url = goal.get_translate_url_for_path(pootle_path,
                                                       state='incomplete')
            if goal_words > 0:
                goals_summary.extend([
                    u'<br /><a class="path-incomplete" href="%(url)s">' % {
                            'url': goal_url,
                        },
                    ungettext(u'Next most important goal (%(num)d word left)',
                              u'Next most important goal (%(num)d words left)',
                              goal_words,
                              {'num': goal_words, }),
                ])

    return {'is_dir': path_obj.is_dir,
            'goals_summary': u''.join(goals_summary),
            'summary_more_url': url_path_summary_more,
            'translate_url': path_obj.get_translate_url(state='all'),
            'incomplete_url': path_obj.get_translate_url(state='incomplete'),
            'suggestions_url': path_obj.get_translate_url(state='suggestions')}
Example #11
0
    def handle(self, *args, **options):
        """Add project goals from file to the given project."""
        project_name = options.get('project_name', None)
        goals_filename = options.get('goals_file', None)

        if project_name is None:
            raise CommandError("A project must be provided.")
        elif goals_filename is None:
            raise CommandError("A filename must be provided.")
        elif not os.path.isfile(goals_filename):
            raise CommandError("Filename '%s' doesn't point to an existing "
                               "file." % goals_filename)

        try:
            project = Project.objects.get(code=project_name)
        except Project.DoesNotExist:
            raise CommandError("Project '%s' does not exist." % project_name)

        template_tp = project.get_template_translationproject()

        if not template_tp:
            raise CommandError("Project '%s' doesn't have a template "
                               "translation project." % project_name)

        try:
            inputfile = open(goals_filename, "r")
            inputlines = inputfile.readlines()
            inputfile.close()
        except IOError as e:
            raise CommandError("Some error occurred while handling the file: "
                               "%s" % e.strerror)

        line_number = 0
        goals_dict = {}
        template_language = template_tp.language.code

        for line in inputlines:
            line_number += 1
            line.strip()

            try:
                goal_name, filename = line.split("\t")
            except ValueError:
                raise CommandError("Wrong syntax at line %d." % line_number)

            # Polish the goal name and filename before working with them.
            filename = filename.strip().lstrip("./")
            filename = "/".join([project_name, template_language, filename])
            goal_name = goal_name.lower()

            if not goal_name.startswith("goal:"):
                goal_name = "goal:" + goal_name

            try:
                goals_dict[goal_name].append(filename)
            except KeyError:
                goals_dict[goal_name] = [filename]

        logging.info("\nParsed %d lines from '%s'\n", line_number,
                     goals_filename)

        # First check if any of the goals already exists and it is not a
        # project goal, in order to abort before creating or adding any of the
        # goals to the files.
        for goal_name in goals_dict.keys():
            try:
                goal = Goal.objects.get(name=goal_name)

                if not goal.project_goal:
                    raise CommandError("The goal '%s' already exists but it "
                                       "isn't a project goal." % goal)
            except Goal.DoesNotExist:
                pass

        # Criteria to get all the items in a random goal that correspond to
        # stores in the 'templates' translation project.
        #
        # It is used several lines below, but here is possible to calculate it
        # just once.
        stores_criteria = {
            'content_type': ContentType.objects.get_for_model(Store),
            'object_id__in': template_tp.stores.values_list('pk', flat=True),
        }

        applied_goals = set()

        # Now apply the goal to each of the stores.
        for goal_name in goals_dict.keys():
            try:
                # Retrieve the goal if it already exists.
                goal = Goal.objects.get(name=goal_name)

                # Unapply the goal from all the stores in the 'templates'
                # translation project to which the goal is currently applied.
                goal.items_with_goal.filter(**stores_criteria).delete()
            except Goal.DoesNotExist:
                # If the goal doesn't exist yet then create it.
                criteria = {
                    'name': goal_name,
                    # Note: for some unknown reason it is necessary to provide
                    # the slug instead of letting the model create it.
                    'slug': slugify_tag_name(goal_name),
                    'project_goal': True,
                }

                try:
                    # Get the goal priority from the end of the goal name.
                    criteria['priority'] = int(goal_name[-1])
                except ValueError:
                    pass

                goal = Goal(**criteria)
                goal.save()

            for filename in goals_dict[goal_name]:
                try:
                    store = template_tp.stores.get(file=filename)
                    store.goals.add(goal)
                    applied_goals.add(goal_name)
                    logging.info("Goal '%s' applied to '%s'.", goal_name,
                                 filename)
                except ObjectDoesNotExist:
                    logging.warning(
                        "File '%s' is not on the template "
                        "language. Skipping it.\n", filename)

        logging.info("\nSucessfully added %d project goals to project '%s'.",
                     len(applied_goals), project_name)
Example #12
0
def overview(request,
             translation_project,
             dir_path,
             filename=None,
             goal=None,
             in_goal_overview=False):
    current_path = translation_project.directory.pootle_path + dir_path

    if filename:
        current_path = current_path + filename
        store = get_object_or_404(Store, pootle_path=current_path)
        directory = store.parent
        ctx = {
            'store_tags': store.tag_like_objects,
        }
        template_name = "translation_projects/store_overview.html"
    else:
        store = None
        directory = get_object_or_404(Directory, pootle_path=current_path)
        ctx = {
            'tp_tags': translation_project.tag_like_objects,
        }
        template_name = "translation_projects/overview.html"

    if (check_permission('translate', request)
            or check_permission('suggest', request)
            or check_permission('overwrite', request)):

        ctx.update({
            'upload_form':
            _handle_upload_form(request, current_path, translation_project,
                                directory),
        })

    can_edit = check_permission('administrate', request)

    project = translation_project.project
    language = translation_project.language

    path_obj = store or directory

    #TODO enable again some actions when drilling down a goal.
    if goal is None:
        actions = action_groups(request, path_obj)
    else:
        actions = []

    action_output = ''
    running = request.GET.get(EXTDIR, '')

    #TODO enable the following again when drilling down a goal.
    if running and goal is None:
        if store:
            act = StoreAction
        else:
            act = TranslationProjectAction
        try:
            action = act.lookup(running)
        except KeyError:
            messages.error(
                request,
                _("Unable to find '%(action)s' in '%(extdir)s'") % {
                    'action': act,
                    'extdir': running
                })
        else:
            if not getattr(action, 'nosync', False):
                (store or translation_project).sync()
            if action.is_active(request):
                vcs_dir = settings.VCS_DIRECTORY
                po_dir = settings.PODIRECTORY
                tp_dir = directory.get_real_path()
                store_fn = '*'
                if store:
                    tp_dir_slash = add_trailing_slash(tp_dir)
                    if store.file.name.startswith(tp_dir_slash):
                        # Note: store_f used below in reverse() call.
                        store_f = store.file.name[len(tp_dir_slash):]
                        store_fn = store_f.replace('/', os.sep)

                # Clear possibly stale output/error (even from other path_obj).
                action.set_output('')
                action.set_error('')
                try:
                    action.run(path=path_obj,
                               root=po_dir,
                               tpdir=tp_dir,
                               project=project.code,
                               language=language.code,
                               store=store_fn,
                               style=translation_project.file_style,
                               vc_root=vcs_dir)
                except StandardError:
                    err = (_("Error while running '%s' extension action") %
                           action.title)
                    logging.exception(err)
                    if (action.error):
                        messages.error(request, action.error)
                    else:
                        messages.error(request, err)
                else:
                    if (action.error):
                        messages.warning(request, action.error)

                action_output = action.output
                if getattr(action, 'get_download', None):
                    export_path = action.get_download(path_obj)
                    if export_path:
                        import mimetypes
                        abs_path = absolute_real_path(export_path)
                        filename = os.path.basename(export_path)
                        mimetype, encoding = mimetypes.guess_type(filename)
                        mimetype = mimetype or 'application/octet-stream'
                        with open(abs_path, 'rb') as f:
                            response = HttpResponse(f.read(),
                                                    mimetype=mimetype)
                        response['Content-Disposition'] = (
                            'attachment; filename="%s"' % filename)
                        return response

                if not action_output:
                    if not store:
                        rev_args = [language.code, project.code, '']
                        overview_url = reverse('pootle-tp-overview',
                                               args=rev_args)
                    else:
                        slash = store_f.rfind('/')
                        store_d = ''
                        if slash > 0:
                            store_d = store_f[:slash]
                            store_f = store_f[slash + 1:]
                        elif slash == 0:
                            store_f = store_f[1:]
                        rev_args = [
                            language.code, project.code, store_d, store_f
                        ]
                        overview_url = reverse('pootle-tp-overview',
                                               args=rev_args)
                    return HttpResponseRedirect(overview_url)

    if goal is None:
        description = translation_project.description
    else:
        description = goal.description

    ctx.update({
        'resource_obj': request.resource_obj,
        'translation_project': translation_project,
        'description': description,
        'project': project,
        'language': language,
        'path_obj': path_obj,
        'resource_path': request.resource_path,
        'topstats': gentopstats_translation_project(translation_project),
        'feed_path': directory.pootle_path[1:],
        'action_groups': actions,
        'action_output': action_output,
        'can_edit': can_edit,
    })

    tp_pootle_path = translation_project.pootle_path

    if store is None:
        path_obj_goals = Goal.get_goals_for_path(path_obj.pootle_path)
        path_obj_has_goals = len(path_obj_goals) > 0

        if in_goal_overview and path_obj_has_goals:
            # Then show the goals tab.
            table_fields = [
                'name', 'progress', 'priority', 'total', 'need-translation',
                'suggestions'
            ]
            items = [
                make_goal_item(path_obj_goal, path_obj.pootle_path)
                for path_obj_goal in path_obj_goals
            ]
            ctx.update({
                'table': {
                    'id': 'tp-goals',
                    'proportional': False,
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'parent': get_parent(directory),
                    'items': items,
                },
                'path_obj_has_goals': True,
            })
        elif goal in path_obj_goals:
            # Then show the drill down view for the specified goal.
            table_fields = [
                'name', 'progress', 'total', 'need-translation', 'suggestions'
            ]

            ctx.update({
                'table': {
                    'id': 'tp-goals',
                    'proportional': True,
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'parent': get_goal_parent(directory, goal),
                    'items': get_goal_children(directory, goal),
                },
                'goal':
                goal,
                'goal_url':
                goal.get_drill_down_url_for_path(tp_pootle_path),
                'path_obj_has_goals':
                True,
            })
        else:
            # Then show the files tab.
            table_fields = [
                'name', 'progress', 'total', 'need-translation', 'suggestions'
            ]
            ctx.update({
                'table': {
                    'id': 'tp-files',
                    'proportional': True,
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'parent': get_parent(directory),
                    'items': get_children(directory),
                },
                'path_obj_has_goals': path_obj_has_goals,
            })
    elif goal is not None:
        ctx.update({
            'goal':
            goal,
            'goal_url':
            goal.get_drill_down_url_for_path(tp_pootle_path),
        })

    if can_edit:
        if store is None:
            url_kwargs = {
                'language_code': language.code,
                'project_code': project.code,
            }
            add_tag_action_url = reverse('pootle-xhr-tag-tp',
                                         kwargs=url_kwargs)
        else:
            add_tag_action_url = reverse('pootle-xhr-tag-store',
                                         args=[path_obj.pk])

        if goal is None:
            edit_form = DescriptionForm(instance=translation_project)
            edit_form_action = reverse('pootle-tp-admin-settings',
                                       args=[language.code, project.code])
        else:
            edit_form = GoalForm(instance=goal)
            edit_form_action = reverse('pootle-xhr-edit-goal',
                                       args=[goal.slug])

        ctx.update({
            'form': edit_form,
            'form_action': edit_form_action,
            'add_tag_form': TagForm(),
            'add_tag_action_url': add_tag_action_url,
        })

    return render_to_response(template_name,
                              ctx,
                              context_instance=RequestContext(request))
Example #13
0
    def all_goals(self):
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        return Goal.get_goals_for_path(self.pootle_path)
Example #14
0
def overview(request, translation_project, dir_path, filename=None,
             goal=None, in_goal_overview=False):

    if filename:
        ctx = {
            'store_tags': request.store.tag_like_objects,
        }
        template_name = "translation_projects/store_overview.html"
    else:
        ctx = {
            'tp_tags': translation_project.tag_like_objects,
        }
        template_name = "browser/overview.html"

    if (check_permission('translate', request) or
        check_permission('suggest', request) or
        check_permission('overwrite', request)):

        ctx.update({
            'upload_form': _handle_upload_form(request, translation_project),
        })

    can_edit = check_permission('administrate', request)

    project = translation_project.project
    language = translation_project.language

    resource_obj = request.store or request.directory

    #TODO enable again some actions when drilling down a goal.
    if goal is None:
        actions = action_groups(request, resource_obj)
    else:
        actions = []

    action_output = ''
    running = request.GET.get(EXTDIR, '')

    #TODO enable the following again when drilling down a goal.
    if running and goal is None:
        if request.store:
            act = StoreAction
        else:
            act = TranslationProjectAction
        try:
            action = act.lookup(running)
        except KeyError:
            messages.error(request, _("Unable to find '%(action)s' in '%(extdir)s'") %
                                      {'action': act, 'extdir': running})
        else:
            if not getattr(action, 'nosync', False):
                (request.store or translation_project).sync()
            if action.is_active(request):
                vcs_dir = settings.VCS_DIRECTORY
                po_dir = settings.PODIRECTORY
                tp_dir = request.directory.get_real_path()
                store_fn = '*'
                if request.store:
                    tp_dir_slash = add_trailing_slash(tp_dir)
                    if request.store.file.name.startswith(tp_dir_slash):
                        # Note: store_f used below in reverse() call.
                        store_f = request.store.file.name[len(tp_dir_slash):]
                        store_fn = store_f.replace('/', os.sep)

                # Clear possibly stale output/error (even from other
                # resource_obj).
                action.set_output('')
                action.set_error('')
                try:
                    action.run(path=resource_obj, root=po_dir, tpdir=tp_dir,
                               project=project.code, language=language.code,
                               store=store_fn,
                               style=translation_project.file_style,
                               vc_root=vcs_dir)
                except StandardError:
                    err = (_("Error while running '%s' extension action") %
                           action.title)
                    logging.exception(err)
                    if (action.error):
                        messages.error(request, action.error)
                    else:
                        messages.error(request, err)
                else:
                    if (action.error):
                        messages.warning(request, action.error)

                action_output = action.output
                if getattr(action, 'get_download', None):
                    export_path = action.get_download(resource_obj)
                    if export_path:
                        import mimetypes
                        abs_path = absolute_real_path(export_path)
                        filename = os.path.basename(export_path)
                        mimetype, encoding = mimetypes.guess_type(filename)
                        mimetype = mimetype or 'application/octet-stream'
                        with open(abs_path, 'rb') as f:
                            response = HttpResponse(f.read(),
                                                    mimetype=mimetype)
                        response['Content-Disposition'] = (
                                'attachment; filename="%s"' % filename)
                        return response

                if not action_output:
                    if not request.store:
                        rev_args = [language.code, project.code, '']
                        overview_url = reverse('pootle-tp-overview',
                                               args=rev_args)
                    else:
                        slash = store_f.rfind('/')
                        store_d = ''
                        if slash > 0:
                            store_d = store_f[:slash]
                            store_f = store_f[slash + 1:]
                        elif slash == 0:
                            store_f = store_f[1:]
                        rev_args = [language.code, project.code, store_d,
                                    store_f]
                        overview_url = reverse('pootle-tp-overview',
                                               args=rev_args)
                    return HttpResponseRedirect(overview_url)

    if goal is None:
        description = translation_project.description
    else:
        description = goal.description

    ctx.update(get_overview_context(request))
    ctx.update({
        'resource_obj': request.store or request.directory,  # Dirty hack.
        'translation_project': translation_project,
        'description': description,
        'project': project,
        'language': language,
        'feed_path': request.directory.pootle_path[1:],
        'action_groups': actions,
        'action_output': action_output,
        'can_edit': can_edit,

        'browser_extends': 'translation_projects/base.html',
        'browser_body_id': 'tpoverview',
    })

    tp_pootle_path = translation_project.pootle_path

    if request.store is None:
        resource_obj_goals = Goal.get_goals_for_path(resource_obj.pootle_path)
        resource_obj_has_goals = len(resource_obj_goals) > 0

        if in_goal_overview and resource_obj_has_goals:
            # Then show the goals tab.
            table_fields = ['name', 'progress', 'priority', 'total',
                            'need-translation', 'suggestions']
            items = [make_goal_item(resource_obj_goal, resource_obj.pootle_path)
                     for resource_obj_goal in resource_obj_goals]
            ctx.update({
                'table': {
                    'id': 'tp-goals',
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'parent': get_parent(request.directory),
                    'items': items,
                },
                'resource_obj_has_goals': True,
            })
        elif goal in resource_obj_goals:
            # Then show the drill down view for the specified goal.
            table_fields = ['name', 'progress', 'total', 'need-translation',
                            'suggestions', 'critical', 'activity']

            ctx.update({
                'table': {
                    'id': 'tp-goals',
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'parent': get_goal_parent(request.directory, goal),
                    'items': get_goal_children(request.directory, goal),
                },
                'goal': goal,
                'goal_url': goal.get_drill_down_url_for_path(tp_pootle_path),
                'resource_obj_has_goals': True,
            })
        else:
            # Then show the files tab.
            table_fields = ['name', 'progress', 'total', 'need-translation',
                            'suggestions', 'critical', 'activity']
            ctx.update({
                'table': {
                    'id': 'tp-files',
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'parent': get_parent(request.directory),
                    'items': get_children(request.directory),
                },
                'resource_obj_has_goals': resource_obj_has_goals,
            })
    elif goal is not None:
        ctx.update({
            'goal': goal,
            'goal_url': goal.get_drill_down_url_for_path(tp_pootle_path),
        })

    if can_edit:
        if request.store is None:
            url_kwargs = {
                'language_code': language.code,
                'project_code': project.code,
            }
            add_tag_action_url = reverse('pootle-xhr-tag-tp',
                                         kwargs=url_kwargs)
        else:
            add_tag_action_url = reverse('pootle-xhr-tag-store',
                                         args=[resource_obj.pk])

        if goal is None:
            edit_form = DescriptionForm(instance=translation_project)
            edit_form_action = reverse('pootle-tp-admin-settings',
                                       args=[language.code, project.code])
        else:
            edit_form = GoalForm(instance=goal)
            edit_form_action = reverse('pootle-xhr-edit-goal',
                                       args=[goal.slug])

        ctx.update({
            'form': edit_form,
            'form_action': edit_form_action,
            'add_tag_form': TagForm(),
            'add_tag_action_url': add_tag_action_url,
        })

    return render_to_response(template_name, ctx,
                              context_instance=RequestContext(request))
Example #15
0
    def handle(self, *args, **options):
        """Add project goals from file to the given project."""
        project_name = options.get('project_name', None)
        goals_filename = options.get('goals_file', None)

        if project_name is None:
            raise CommandError("A project must be provided.")
        elif goals_filename is None:
            raise CommandError("A filename must be provided.")
        elif not os.path.isfile(goals_filename):
            raise CommandError("Filename '%s' doesn't point to an existing "
                               "file." % goals_filename)

        try:
            project = Project.objects.get(code=project_name)
        except Project.DoesNotExist:
            raise CommandError("Project '%s' does not exist." %
                               project_name)

        template_tp = project.get_template_translationproject()

        if not template_tp:
            raise CommandError("Project '%s' doesn't have a template "
                               "translation project." % project_name)

        try:
            inputfile = open(goals_filename, "r")
            inputlines = inputfile.readlines()
            inputfile.close()
        except IOError as e:
            raise CommandError("Some error occurred while handling the file: "
                               "%s" % e.strerror)

        line_number = 0
        goals_dict = {}
        template_language = template_tp.language.code

        for line in inputlines:
            line_number += 1
            line.strip()

            try:
                goal_name, filename = line.split("\t")
            except ValueError:
                raise CommandError("Wrong syntax at line %d." % line_number)

            # Polish the goal name and filename before working with them.
            filename = filename.strip().lstrip("./")
            filename = "/".join([project_name, template_language, filename])
            goal_name = goal_name.lower()

            if not goal_name.startswith("goal:"):
                goal_name = "goal:" + goal_name

            try:
                goals_dict[goal_name].append(filename)
            except KeyError:
                goals_dict[goal_name] = [filename]

        logging.info("\nParsed %d lines from '%s'\n", line_number,
                     goals_filename)

        # First check if any of the goals already exists and it is not a
        # project goal, in order to abort before creating or adding any of the
        # goals to the files.
        for goal_name in goals_dict.keys():
            try:
                goal = Goal.objects.get(name=goal_name)

                if not goal.project_goal:
                    raise CommandError("The goal '%s' already exists but it "
                                       "isn't a project goal." % goal)
            except Goal.DoesNotExist:
                pass

        # Criteria to get all the items in a random goal that correspond to
        # stores in the 'templates' translation project.
        #
        # It is used several lines below, but here is possible to calculate it
        # just once.
        stores_criteria = {
            'content_type': ContentType.objects.get_for_model(Store),
            'object_id__in': template_tp.stores.values_list('pk', flat=True),
        }

        applied_goals = set()

        # Now apply the goal to each of the stores.
        for goal_name in goals_dict.keys():
            try:
                # Retrieve the goal if it already exists.
                goal = Goal.objects.get(name=goal_name)

                # Unapply the goal from all the stores in the 'templates'
                # translation project to which the goal is currently applied.
                goal.items_with_goal.filter(**stores_criteria).delete()
            except Goal.DoesNotExist:
                # If the goal doesn't exist yet then create it.
                criteria = {
                    'name': goal_name,
                    # Note: for some unknown reason it is necessary to provide
                    # the slug instead of letting the model create it.
                    'slug': slugify_tag_name(goal_name),
                    'project_goal': True,
                }

                try:
                    # Get the goal priority from the end of the goal name.
                    criteria['priority'] = int(goal_name[-1])
                except ValueError:
                    pass

                goal = Goal(**criteria)
                goal.save()

            for filename in goals_dict[goal_name]:
                try:
                    store = template_tp.stores.get(file=filename)
                    store.goals.add(goal)
                    applied_goals.add(goal_name)
                    logging.info("Goal '%s' applied to '%s'.", goal_name,
                                 filename)
                except ObjectDoesNotExist:
                    logging.warning("File '%s' is not on the template "
                                    "language. Skipping it.\n", filename)

        logging.info("\nSucessfully added %d project goals to project '%s'.",
                     len(applied_goals), project_name)
Example #16
0
def get_path_summary(path_obj, path_stats, latest_action):
    """Returns a list of sentences to be displayed for each ``path_obj``."""
    summary = []
    incomplete = []
    suggestions = []

    if path_obj.is_dir:
        summary.append(
            ungettext("This folder has %(num)d word, %(percentage)d%% of "
                "which is translated.",
                "This folder has %(num)d words, %(percentage)d%% of "
                "which are translated.",
                path_stats['total']['words'],
                {
                    'num': path_stats['total']['words'],
                    'percentage': path_stats['translated']['percentage']
                })
        )
    else:
        summary.append(
            ungettext("This file has %(num)d word, %(percentage)d%% of "
                "which is translated.",
                "This file has %(num)d words, %(percentage)d%% of "
                "which are translated.",
                path_stats['total']['words'],
                {
                    'num': path_stats['total']['words'],
                    'percentage': path_stats['translated']['percentage']
                })
        )

    tp = path_obj.translation_project
    project = tp.project
    language = tp.language

    # Build URL for getting more summary information for the current path
    url_args = [language.code, project.code, path_obj.path]
    url_path_summary_more = reverse('tp.path_summary_more', args=url_args)

    summary.append(u''.join([
        ' <a id="js-path-summary" data-target="js-path-summary-more" '
        'href="%s">' % url_path_summary_more,
        force_unicode(_(u'Expand details')),
        '</a>'
    ]))


    if path_stats['untranslated']['words'] > 0 or path_stats['fuzzy']['words'] > 0:
        num_words = path_stats['untranslated']['words'] + path_stats['fuzzy']['words']
        incomplete.extend([
            u'<a class="path-incomplete" href="%(url)s">' % {
                    'url': path_obj.get_translate_url(state='incomplete')
                },
            ungettext(u'Continue translation (%(num)d word left)',
                      u'Continue translation (%(num)d words left)',
                      num_words,
                      {'num': num_words, }),
        ])

        if path_obj.is_dir:
            # Putting the next import at the top of the file causes circular
            # import issues.
            from pootle_tagging.models import Goal

            pootle_path = path_obj.pootle_path
            goal = Goal.get_most_important_incomplete_for_path(pootle_path)

            if goal is not None:
                goal_words = goal.get_incomplete_words_in_path(pootle_path)
                goal_url = goal.get_translate_url_for_path(pootle_path,
                                                           state='incomplete')
                incomplete.extend([
                    u'<br /><a class="path-incomplete" href="%(url)s">' % {
                            'url': goal_url,
                        },
                    ungettext(u'Next most important goal (%(num)d word left)',
                              u'Next most important goal (%(num)d words left)',
                              goal_words,
                              {'num': goal_words, }),
                ])
    else:
        incomplete.extend([
            u'<a class="path-incomplete" href="%(url)s">' % {
                    'url': path_obj.get_translate_url(state='all')
                },
            force_unicode(_('Translation is complete')),
        ])

    incomplete.append(u'</a>')


    if path_stats['suggestions'] > 0:
        suggestions.append(u'<a class="path-incomplete" href="%(url)s">' % {
            'url': path_obj.get_translate_url(state='suggestions')
        })
        suggestions.append(
            ungettext(u'Review suggestion (%(num)d left)',
                      u'Review suggestions (%(num)d left)',
                      path_stats['suggestions'],
                      {'num': path_stats['suggestions'], })
        )
        suggestions.append(u'</a>')

    return [u''.join(summary), latest_action, u''.join(incomplete),
            u''.join(suggestions)]
Example #17
0
def overview(request, translation_project, dir_path, filename=None,
             goal=None, in_goal_overview=False):

    if filename:
        ctx = {
            'store_tags': request.store.tag_like_objects,
        }
        template_name = "translation_projects/store_overview.html"
    else:
        ctx = {
            'tp_tags': translation_project.tag_like_objects,
        }
        template_name = "browser/overview.html"

    if (check_permission('translate', request) or
        check_permission('suggest', request) or
        check_permission('overwrite', request)):

        ctx.update({
            'upload_form': _handle_upload_form(request, translation_project),
        })

    can_edit = check_permission('administrate', request)

    project = translation_project.project
    language = translation_project.language

    resource_obj = request.store or request.directory

    #TODO enable again some actions when drilling down a goal.
    if goal is None:
        actions = action_groups(request, resource_obj)
    else:
        actions = []

    action_output = ''
    running = request.GET.get(EXTDIR, '')

    #TODO enable the following again when drilling down a goal.
    if running and goal is None:
        if request.store:
            act = StoreAction
        else:
            act = TranslationProjectAction
        try:
            action = act.lookup(running)
        except KeyError:
            messages.error(request, _("Unable to find '%(action)s' in '%(extdir)s'") %
                                      {'action': act, 'extdir': running})
        else:
            if not getattr(action, 'nosync', False):
                (request.store or translation_project).sync()
            if action.is_active(request):
                vcs_dir = settings.VCS_DIRECTORY
                po_dir = settings.PODIRECTORY
                tp_dir = request.directory.get_real_path()
                store_fn = '*'
                if request.store:
                    tp_dir_slash = add_trailing_slash(tp_dir)
                    if request.store.file.name.startswith(tp_dir_slash):
                        # Note: store_f used below in reverse() call.
                        store_f = request.store.file.name[len(tp_dir_slash):]
                        store_fn = store_f.replace('/', os.sep)

                # Clear possibly stale output/error (even from other
                # resource_obj).
                action.set_output('')
                action.set_error('')
                try:
                    action.run(path=resource_obj, root=po_dir, tpdir=tp_dir,
                               project=project.code, language=language.code,
                               store=store_fn,
                               style=translation_project.file_style,
                               vc_root=vcs_dir)
                except StandardError:
                    err = (_("Error while running '%s' extension action") %
                           action.title)
                    logging.exception(err)
                    if (action.error):
                        messages.error(request, action.error)
                    else:
                        messages.error(request, err)
                else:
                    if (action.error):
                        messages.warning(request, action.error)

                action_output = action.output
                if getattr(action, 'get_download', None):
                    export_path = action.get_download(resource_obj)
                    if export_path:
                        import mimetypes
                        abs_path = absolute_real_path(export_path)
                        filename = os.path.basename(export_path)
                        mimetype, encoding = mimetypes.guess_type(filename)
                        mimetype = mimetype or 'application/octet-stream'
                        with open(abs_path, 'rb') as f:
                            response = HttpResponse(f.read(),
                                                    mimetype=mimetype)
                        response['Content-Disposition'] = (
                                'attachment; filename="%s"' % filename)
                        return response

                if not action_output:
                    if not request.store:
                        rev_args = [language.code, project.code, '']
                        overview_url = reverse('pootle-tp-overview',
                                               args=rev_args)
                    else:
                        slash = store_f.rfind('/')
                        store_d = ''
                        if slash > 0:
                            store_d = store_f[:slash]
                            store_f = store_f[slash + 1:]
                        elif slash == 0:
                            store_f = store_f[1:]
                        rev_args = [language.code, project.code, store_d,
                                    store_f]
                        overview_url = reverse('pootle-tp-overview',
                                               args=rev_args)
                    return HttpResponseRedirect(overview_url)

    if goal is None:
        description = translation_project.description
    else:
        description = goal.description

    # TODO: cleanup and refactor, retrieve from cache
    try:
        ann_virtual_path = 'announcements/' + project.code
        announcement = StaticPage.objects.live(request.user).get(
            virtual_path=ann_virtual_path,
        )
    except StaticPage.DoesNotExist:
        announcement = None

    display_announcement = True
    stored_mtime = None
    new_mtime = None
    cookie_data = {}

    if ANN_COOKIE_NAME in request.COOKIES:
        json_str = unquote(request.COOKIES[ANN_COOKIE_NAME])
        cookie_data = simplejson.loads(json_str)

        if 'isOpen' in cookie_data:
            display_announcement = cookie_data['isOpen']

        if project.code in cookie_data:
            stored_mtime = cookie_data[project.code]

    if announcement is not None:
        ann_mtime = dateformat.format(announcement.modified_on, 'U')
        if ann_mtime != stored_mtime:
            display_announcement = True
            new_mtime = ann_mtime

    ctx.update(get_overview_context(request))
    ctx.update({
        'resource_obj': request.store or request.directory,  # Dirty hack.
        'translation_project': translation_project,
        'description': description,
        'project': project,
        'language': language,
        'feed_path': request.directory.pootle_path[1:],
        'action_groups': actions,
        'action_output': action_output,
        'can_edit': can_edit,

        'browser_extends': 'translation_projects/base.html',
        'browser_body_id': 'tpoverview',

        'announcement': announcement,
        'announcement_displayed': display_announcement,
    })

    tp_pootle_path = translation_project.pootle_path

    if request.store is None:
        resource_obj_goals = Goal.get_goals_for_path(resource_obj.pootle_path)
        resource_obj_has_goals = len(resource_obj_goals) > 0

        if in_goal_overview and resource_obj_has_goals:
            # Then show the goals tab.
            table_fields = ['name', 'progress', 'priority', 'total',
                            'need-translation', 'suggestions']
            items = [make_goal_item(resource_obj_goal, resource_obj.pootle_path)
                     for resource_obj_goal in resource_obj_goals]
            ctx.update({
                'table': {
                    'id': 'tp-goals',
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'parent': get_parent(request.directory),
                    'items': items,
                },
                'resource_obj_has_goals': True,
            })
        elif goal in resource_obj_goals:
            # Then show the drill down view for the specified goal.
            table_fields = ['name', 'progress', 'total', 'need-translation',
                            'suggestions', 'critical', 'last-updated',
                            'activity']

            ctx.update({
                'table': {
                    'id': 'tp-goals',
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'parent': get_goal_parent(request.directory, goal),
                    'items': get_goal_children(request.directory, goal),
                },
                'goal': goal,
                'goal_url': goal.get_drill_down_url_for_path(tp_pootle_path),
                'resource_obj_has_goals': True,
            })
        else:
            # Then show the files tab.
            table_fields = ['name', 'progress', 'total', 'need-translation',
                            'suggestions', 'critical', 'last-updated',
                            'activity']
            ctx.update({
                'table': {
                    'id': 'tp-files',
                    'fields': table_fields,
                    'headings': get_table_headings(table_fields),
                    'parent': get_parent(request.directory),
                    'items': get_children(request.directory),
                },
                'resource_obj_has_goals': resource_obj_has_goals,
            })
    elif goal is not None:
        ctx.update({
            'goal': goal,
            'goal_url': goal.get_drill_down_url_for_path(tp_pootle_path),
        })

    if can_edit:
        if request.store is None:
            url_kwargs = {
                'language_code': language.code,
                'project_code': project.code,
            }
            add_tag_action_url = reverse('pootle-xhr-tag-tp',
                                         kwargs=url_kwargs)
        else:
            add_tag_action_url = reverse('pootle-xhr-tag-store',
                                         args=[resource_obj.pk])

        if goal is None:
            edit_form = DescriptionForm(instance=translation_project)
            edit_form_action = reverse('pootle-tp-admin-settings',
                                       args=[language.code, project.code])
        else:
            edit_form = GoalForm(instance=goal)
            edit_form_action = reverse('pootle-xhr-edit-goal',
                                       args=[goal.slug])

        ctx.update({
            'form': edit_form,
            'form_action': edit_form_action,
            'add_tag_form': TagForm(),
            'add_tag_action_url': add_tag_action_url,
        })

    response = render_to_response(template_name, ctx,
                                  context_instance=RequestContext(request))

    if new_mtime is not None:
        cookie_data[project.code] = new_mtime
        cookie_data = quote(simplejson.dumps(cookie_data))
        response.set_cookie(ANN_COOKIE_NAME, cookie_data)

    return response
Example #18
0
def overview(request, translation_project, dir_path, filename=None, goal=None, in_goal_overview=False):

    if filename:
        ctx = {"store_tags": request.store.tag_like_objects}
        template_name = "translation_projects/store_overview.html"
    else:
        ctx = {"tp_tags": translation_project.tag_like_objects}
        template_name = "browser/overview.html"

    if (
        check_permission("translate", request)
        or check_permission("suggest", request)
        or check_permission("overwrite", request)
    ):

        ctx.update({"upload_form": _handle_upload_form(request, translation_project)})

    can_edit = check_permission("administrate", request)

    project = translation_project.project
    language = translation_project.language

    resource_obj = request.store or request.directory

    # TODO enable again some actions when drilling down a goal.
    if goal is None:
        actions = action_groups(request, resource_obj)
    else:
        actions = []

    action_output = ""
    running = request.GET.get(EXTDIR, "")

    # TODO enable the following again when drilling down a goal.
    if running and goal is None:
        if request.store:
            act = StoreAction
        else:
            act = TranslationProjectAction
        try:
            action = act.lookup(running)
        except KeyError:
            messages.error(
                request, _("Unable to find '%(action)s' in '%(extdir)s'") % {"action": act, "extdir": running}
            )
        else:
            if not getattr(action, "nosync", False):
                (request.store or translation_project).sync()
            if action.is_active(request):
                vcs_dir = settings.VCS_DIRECTORY
                po_dir = settings.PODIRECTORY
                tp_dir = request.directory.get_real_path()
                store_fn = "*"
                if request.store:
                    tp_dir_slash = add_trailing_slash(tp_dir)
                    if request.store.file.name.startswith(tp_dir_slash):
                        # Note: store_f used below in reverse() call.
                        store_f = request.store.file.name[len(tp_dir_slash) :]
                        store_fn = store_f.replace("/", os.sep)

                # Clear possibly stale output/error (even from other
                # resource_obj).
                action.set_output("")
                action.set_error("")
                try:
                    action.run(
                        path=resource_obj,
                        root=po_dir,
                        tpdir=tp_dir,
                        project=project.code,
                        language=language.code,
                        store=store_fn,
                        style=translation_project.file_style,
                        vc_root=vcs_dir,
                    )
                except StandardError:
                    err = _("Error while running '%s' extension action") % action.title
                    logging.exception(err)
                    if action.error:
                        messages.error(request, action.error)
                    else:
                        messages.error(request, err)
                else:
                    if action.error:
                        messages.warning(request, action.error)

                action_output = action.output
                if getattr(action, "get_download", None):
                    export_path = action.get_download(resource_obj)
                    if export_path:
                        import mimetypes

                        abs_path = absolute_real_path(export_path)
                        filename = os.path.basename(export_path)
                        mimetype, encoding = mimetypes.guess_type(filename)
                        mimetype = mimetype or "application/octet-stream"
                        with open(abs_path, "rb") as f:
                            response = HttpResponse(f.read(), mimetype=mimetype)
                        response["Content-Disposition"] = 'attachment; filename="%s"' % filename
                        return response

                if not action_output:
                    if not request.store:
                        rev_args = [language.code, project.code, ""]
                        overview_url = reverse("pootle-tp-overview", args=rev_args)
                    else:
                        slash = store_f.rfind("/")
                        store_d = ""
                        if slash > 0:
                            store_d = store_f[:slash]
                            store_f = store_f[slash + 1 :]
                        elif slash == 0:
                            store_f = store_f[1:]
                        rev_args = [language.code, project.code, store_d, store_f]
                        overview_url = reverse("pootle-tp-overview", args=rev_args)
                    return HttpResponseRedirect(overview_url)

    if goal is None:
        description = translation_project.description
    else:
        description = goal.description

    ctx.update(get_overview_context(request))
    ctx.update(
        {
            "resource_obj": request.store or request.directory,  # Dirty hack.
            "translation_project": translation_project,
            "description": description,
            "project": project,
            "language": language,
            "feed_path": request.directory.pootle_path[1:],
            "action_groups": actions,
            "action_output": action_output,
            "can_edit": can_edit,
            "browser_extends": "translation_projects/base.html",
            "browser_body_id": "tpoverview",
        }
    )

    tp_pootle_path = translation_project.pootle_path

    if request.store is None:
        resource_obj_goals = Goal.get_goals_for_path(resource_obj.pootle_path)
        resource_obj_has_goals = len(resource_obj_goals) > 0

        if in_goal_overview and resource_obj_has_goals:
            # Then show the goals tab.
            table_fields = ["name", "progress", "priority", "total", "need-translation", "suggestions"]
            items = [
                make_goal_item(resource_obj_goal, resource_obj.pootle_path) for resource_obj_goal in resource_obj_goals
            ]
            ctx.update(
                {
                    "table": {
                        "id": "tp-goals",
                        "fields": table_fields,
                        "headings": get_table_headings(table_fields),
                        "parent": get_parent(request.directory),
                        "items": items,
                    },
                    "resource_obj_has_goals": True,
                }
            )
        elif goal in resource_obj_goals:
            # Then show the drill down view for the specified goal.
            table_fields = ["name", "progress", "total", "need-translation", "suggestions", "critical", "activity"]

            ctx.update(
                {
                    "table": {
                        "id": "tp-goals",
                        "fields": table_fields,
                        "headings": get_table_headings(table_fields),
                        "parent": get_goal_parent(request.directory, goal),
                        "items": get_goal_children(request.directory, goal),
                    },
                    "goal": goal,
                    "goal_url": goal.get_drill_down_url_for_path(tp_pootle_path),
                    "resource_obj_has_goals": True,
                }
            )
        else:
            # Then show the files tab.
            table_fields = ["name", "progress", "total", "need-translation", "suggestions", "critical", "activity"]
            ctx.update(
                {
                    "table": {
                        "id": "tp-files",
                        "fields": table_fields,
                        "headings": get_table_headings(table_fields),
                        "parent": get_parent(request.directory),
                        "items": get_children(request.directory),
                    },
                    "resource_obj_has_goals": resource_obj_has_goals,
                }
            )
    elif goal is not None:
        ctx.update({"goal": goal, "goal_url": goal.get_drill_down_url_for_path(tp_pootle_path)})

    if can_edit:
        if request.store is None:
            url_kwargs = {"language_code": language.code, "project_code": project.code}
            add_tag_action_url = reverse("pootle-xhr-tag-tp", kwargs=url_kwargs)
        else:
            add_tag_action_url = reverse("pootle-xhr-tag-store", args=[resource_obj.pk])

        if goal is None:
            edit_form = DescriptionForm(instance=translation_project)
            edit_form_action = reverse("pootle-tp-admin-settings", args=[language.code, project.code])
        else:
            edit_form = GoalForm(instance=goal)
            edit_form_action = reverse("pootle-xhr-edit-goal", args=[goal.slug])

        ctx.update(
            {
                "form": edit_form,
                "form_action": edit_form_action,
                "add_tag_form": TagForm(),
                "add_tag_action_url": add_tag_action_url,
            }
        )

    return render_to_response(template_name, ctx, context_instance=RequestContext(request))
Example #19
0
    def all_goals(self):
        # Putting the next import at the top of the file causes circular
        # import issues.
        from pootle_tagging.models import Goal

        return Goal.get_goals_for_path(self.pootle_path)