Skip to content

Commit

Permalink
Add translator role with 'translated' boolean state on a translation
Browse files Browse the repository at this point in the history
  • Loading branch information
simonprev committed Dec 20, 2023
1 parent d65ab1c commit cfe1e9a
Show file tree
Hide file tree
Showing 41 changed files with 216 additions and 107 deletions.
24 changes: 24 additions & 0 deletions cli/src/commands/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export default class Stats extends Command {
'check-reviewed': flags.boolean({
description: 'Exit 1 when reviewed percentage is not 100%',
}),
'check-translated': flags.boolean({
description: 'Exit 1 when translated percentage is not 100%',
}),
config: configFlag,
};

Expand Down Expand Up @@ -61,5 +64,26 @@ export default class Stats extends Command {
);
}
}

if (flags['check-translated']) {
const translatedCount = this.project!.revisions.reduce(
(memo, revision: Revision) => memo + revision.translatedCount,
0
);
const translationsCount = this.project!.revisions.reduce(
(memo, revision: Revision) => memo + revision.translationsCount,
0
);

if (translationsCount - translatedCount !== 0) {
const versionFormat = flags.version ? ` ${flags.version}` : '';
throw new CLIError(
chalk.red(
`Project${versionFormat} has ${translatedCount} strings to be translated`
),
{exit: 1}
);
}
}
}
}
14 changes: 10 additions & 4 deletions cli/src/services/formatters/project-stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export default class ProjectStatsFormatter extends Base {
(memo, revision: Revision) => memo + revision.translationsCount,
0
);
const translatedCount = this.project.revisions.reduce(
(memo, revision: Revision) => memo + revision.translatedCount,
0
);
const conflictsCount = this.project.revisions.reduce(
(memo, revision: Revision) => memo + revision.conflictsCount,
0
Expand All @@ -79,10 +83,8 @@ export default class ProjectStatsFormatter extends Base {
);

console.log(
this.project.logo
? this.project.logo
: chalk.bgGreenBright.black.bold(' ^ '),
chalk.white.bold(this.project.name),
this.project.logo ? this.project.logo : chalk.bgGreen.black.bold(' ^ '),
chalk.whiteBright.bold(this.project.name),
chalk.dim(' • '),
percentageReviewedFormat
);
Expand Down Expand Up @@ -167,6 +169,10 @@ export default class ProjectStatsFormatter extends Base {
console.log(chalk.magenta(`Strings (${translationsCount})`));
console.log(chalk.green('✓ Reviewed:'), chalk.green(`${reviewedCount}`));
console.log(chalk.red('× In review:'), chalk.red(`${conflictsCount}`));
console.log(
chalk.white('✎ Translated:'),
chalk.white(`${translatedCount}`)
);
console.log('');

const owners = this.project.collaborators.filter(
Expand Down
10 changes: 6 additions & 4 deletions cli/src/services/project-fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ export default class ProjectFetcher {
}

private async graphql(config: Config, params: object) {
const query = `query ProjectDetails($projectId: ID! $versionId: ID) {
const query = `query ProjectDetails($project_id: ID! $version_id: ID) {
viewer {
user {
fullname
}
project(id: $projectId) {
project(id: $project_id) {
id
name
logo
Expand Down Expand Up @@ -88,9 +88,10 @@ export default class ProjectFetcher {
}
}
revisions(versionId: $versionId) {
revisions(versionId: $version_id) {
id
isMaster
translatedCount
translationsCount
conflictsCount
reviewedCount
Expand All @@ -106,7 +107,8 @@ export default class ProjectFetcher {
}
}`;

const configParams = config.project ? {projectId: config.project} : {};
// eslint-disable-next-line camelcase
const configParams = config.project ? {project_id: config.project} : {};
const variables = {...configParams, ...params};

return await fetch(`${config.apiUrl}/graphql`, {
Expand Down
1 change: 1 addition & 0 deletions cli/src/types/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface Revision {
slug: string | null;
language: Language;
isMaster: boolean;
translatedCount: number;
translationsCount: number;
conflictsCount: number;
reviewedCount: number;
Expand Down
2 changes: 1 addition & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ config :accent,
ecto_repos: [Accent.Repo],
version: version

config :accent, Accent.Repo, start_apps_before_migration: [:ssl]
config :accent, Accent.Repo, start_apps_before_migration: [:ssl], stacktrace: true

if config_env() == :dev do
config :accent, Accent.Repo, log: false
Expand Down
19 changes: 14 additions & 5 deletions lib/accent/auth/role_abilities.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ defmodule Accent.RoleAbilities do
@bot_role "bot"
@developer_role "developer"
@reviewer_role "reviewer"
@translator_role "translator"

@read_actions ~w(
lint
Expand Down Expand Up @@ -36,10 +37,6 @@ defmodule Accent.RoleAbilities do
create_comment
delete_comment
update_comment
correct_all_revision
uncorrect_all_revision
correct_translation
uncorrect_translation
update_translation
create_translation_comments_subscription
delete_translation_comments_subscription
Expand Down Expand Up @@ -91,6 +88,13 @@ defmodule Accent.RoleAbilities do
delete_project
)a ++ @developer_actions

@reviewer_actions ~w(
correct_all_revision
uncorrect_all_revision
correct_translation
uncorrect_translation
)a ++ @any_actions

@actions_with_target ~w(machine_translations_translate use_prompt_improve_text)a

def actions_for(role, target)
Expand All @@ -102,6 +106,7 @@ defmodule Accent.RoleAbilities do
def actions_for(@bot_role, target), do: add_actions_with_target(@bot_actions, @bot_role, target)
def actions_for(@developer_role, target), do: add_actions_with_target(@developer_actions, @developer_role, target)
def actions_for(@reviewer_role, target), do: add_actions_with_target(@any_actions, @reviewer_role, target)
def actions_for(@translator_role, target), do: add_actions_with_target(@any_actions, @translator_role, target)

defp add_actions_with_target(actions, role, target) do
Enum.reduce(@actions_with_target, actions, fn action, actions ->
Expand Down Expand Up @@ -141,10 +146,14 @@ defmodule Accent.RoleAbilities do
def can?(@developer_role, unquote(action), _), do: true
end

for action <- @any_actions do
for action <- @reviewer_actions do
def can?(@reviewer_role, unquote(action), _), do: true
end

for action <- @any_actions do
def can?(@translator_role, unquote(action), _), do: true
end

# Fallback if no permission has been found for the user on the project
def can?(_role, _action, _), do: false
end
6 changes: 5 additions & 1 deletion lib/accent/badge_generator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,19 @@ defmodule Accent.BadgeGenerator do
defp label(value, :percentage_reviewed_count), do: "#{value}%25"
defp label(value, :translations_count), do: "#{value}%20strings"
defp label(value, :reviewed_count), do: "#{value}%20reviewed"
defp label(value, :translated_count), do: "#{value}%20translated"
defp label(value, :conflicts_count), do: "#{value}%20conflicts"

defp merge_project_stats(revisions) do
initial_state = %{translations_count: 0, conflicts_count: 0, reviewed_count: 0, translated_count: 0}

revisions
|> Enum.reduce(%{translations_count: 0, conflicts_count: 0, reviewed_count: 0}, fn revision, acc ->
|> Enum.reduce(initial_state, fn revision, acc ->
acc
|> Map.put(:translations_count, acc[:translations_count] + revision.translations_count)
|> Map.put(:conflicts_count, acc[:conflicts_count] + revision.conflicts_count)
|> Map.put(:reviewed_count, acc[:reviewed_count] + revision.reviewed_count)
|> Map.put(:translated_count, acc[:translated_count] + revision.reviewed_count)
end)
|> then(fn
%{translations_count: 0} = stats ->
Expand Down
1 change: 1 addition & 0 deletions lib/accent/schemas/document.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ defmodule Accent.Document do
has_many(:translations, Accent.Translation)

field(:translations_count, :any, virtual: true, default: :not_loaded)
field(:translated_count, :any, virtual: true, default: :not_loaded)
field(:reviewed_count, :any, virtual: true, default: :not_loaded)
field(:conflicts_count, :any, virtual: true, default: :not_loaded)

Expand Down
5 changes: 3 additions & 2 deletions lib/accent/schemas/previous_translation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ defmodule Accent.PreviousTranslation do
field(:conflicted_text, :string, default: "")
field(:conflicted, :boolean, default: false)
field(:removed, :boolean, default: false)
field(:translated, :boolean, default: false)
field(:value_type, :string)
field(:placeholders, {:array, :string}, default: [])
end
Expand All @@ -28,8 +29,8 @@ defmodule Accent.PreviousTranslation do
iex> Accent.PreviousTranslation.from_translation(nil)
%Accent.PreviousTranslation{}
iex> Accent.PreviousTranslation.from_translation(%Accent.Translation{proposed_text: "a", corrected_text: "b", conflicted_text: "c", conflicted: true, removed: false, value_type: "string", placeholders: ["foo"]})
%Accent.PreviousTranslation{proposed_text: "a", corrected_text: "b", conflicted_text: "c", conflicted: true, removed: false, value_type: "string", placeholders: ["foo"]}
iex> Accent.PreviousTranslation.from_translation(%Accent.Translation{translated: true, proposed_text: "a", corrected_text: "b", conflicted_text: "c", conflicted: true, removed: false, value_type: "string", placeholders: ["foo"]})
%Accent.PreviousTranslation{translated: false, proposed_text: "a", corrected_text: "b", conflicted_text: "c", conflicted: true, removed: false, value_type: "string", placeholders: ["foo"]}
"""
def from_translation(nil), do: from_translation(%{})

Expand Down
5 changes: 4 additions & 1 deletion lib/accent/schemas/project.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ defmodule Accent.Project do
field(:locked_file_operations, :boolean, default: false)

field(:translations_count, :any, virtual: true, default: :not_loaded)
field(:translated_count, :any, virtual: true, default: :not_loaded)
field(:reviewed_count, :any, virtual: true, default: :not_loaded)
field(:conflicts_count, :any, virtual: true, default: :not_loaded)

Expand All @@ -30,7 +31,9 @@ defmodule Accent.Project do
has_many(:operations, Accent.Operation)
has_many(:prompts, Accent.Prompt)

has_many(:collaborators, Accent.Collaborator, where: [role: {:in, ["reviewer", "admin", "developer", "owner"]}])
has_many(:collaborators, Accent.Collaborator,
where: [role: {:in, ["reviewer", "admin", "developer", "owner", "translator"]}]
)

has_many(:all_collaborators, Accent.Collaborator)
belongs_to(:language, Accent.Language)
Expand Down
1 change: 1 addition & 0 deletions lib/accent/schemas/revision.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ defmodule Accent.Revision do

field(:translations_count, :any, virtual: true, default: :not_loaded)
field(:reviewed_count, :any, virtual: true, default: :not_loaded)
field(:translated_count, :any, virtual: true, default: :not_loaded)
field(:conflicts_count, :any, virtual: true, default: :not_loaded)

field(:translation_ids, {:array, :string}, virtual: true)
Expand Down
8 changes: 5 additions & 3 deletions lib/accent/schemas/role.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ defmodule Accent.Role do
%{slug: "owner"},
%{slug: "admin"},
%{slug: "developer"},
%{slug: "reviewer"}
%{slug: "reviewer"},
%{slug: "translator"}
]

@doc """
## Examples
iex> Accent.Role.slugs()
["owner", "admin", "developer", "reviewer"]
["owner", "admin", "developer", "reviewer", "translator"]
"""
defmacro slugs, do: Enum.map(@all, &Map.get(&1, :slug))

Expand All @@ -27,7 +28,8 @@ defmodule Accent.Role do
%Accent.Role{slug: "owner"},
%Accent.Role{slug: "admin"},
%Accent.Role{slug: "developer"},
%Accent.Role{slug: "reviewer"}
%Accent.Role{slug: "reviewer"},
%Accent.Role{slug: "translator"}
]
"""
def all, do: Enum.map(@all, &struct(__MODULE__, &1))
Expand Down
2 changes: 2 additions & 0 deletions lib/accent/schemas/translation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ defmodule Accent.Translation do
field(:value_type, :string, default: "string")
field(:plural, :boolean, default: false)
field(:locked, :boolean, default: false)
field(:translated, :boolean, default: false)
field(:placeholders, {:array, :string}, default: [])

belongs_to(:document, Accent.Document)
Expand All @@ -42,6 +43,7 @@ defmodule Accent.Translation do
conflicted
removed
comments_count
translated
file_index
file_comment
value_type
Expand Down
2 changes: 1 addition & 1 deletion lib/accent/scopes/document.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ defmodule Accent.Scopes.Document do
end

@doc """
Fill `translations_count`, `conflicts_count` and `reviewed_count` for documents.
Fill `translations_count`, `conflicts_count`, `translated_count` and `reviewed_count` for documents.
"""
@spec with_stats(Ecto.Queryable.t(), Keyword.t()) :: Ecto.Queryable.t()
def with_stats(query, opts) do
Expand Down
6 changes: 5 additions & 1 deletion lib/accent/scopes/project.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ defmodule Accent.Scopes.Project do
end

@doc """
Fill `translations_count`, `conflicts_count` and `reviewed_count` for projects.
Fill `translations_count`, `conflicts_count`, `translated_count` and `reviewed_count` for projects.
"""
@spec with_stats(Ecto.Queryable.t()) :: Ecto.Queryable.t()
def with_stats(query) do
Expand All @@ -52,15 +52,19 @@ defmodule Accent.Scopes.Project do
)

reviewed = from(translations, where: [conflicted: false])
translated = from(translations, where: [translated: true])

from(
projects in query,
left_join: translations in subquery(translations),
on: translations.field_id == projects.id,
left_join: reviewed in subquery(reviewed),
on: reviewed.field_id == projects.id,
left_join: translated in subquery(translated),
on: translated.field_id == projects.id,
select_merge: %{
translations_count: coalesce(translations.count, 0),
translated_count: coalesce(translated.count, 0),
reviewed_count: coalesce(reviewed.count, 0),
conflicts_count: coalesce(translations.count, 0) - coalesce(reviewed.count, 0)
}
Expand Down
2 changes: 1 addition & 1 deletion lib/accent/scopes/revision.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ defmodule Accent.Scopes.Revision do
end

@doc """
Fill `translations_count`, `conflicts_count` and `reviewed_count` for revisions.
Fill `translations_count`, `conflicts_count`, `translated_count` and `reviewed_count` for revisions.
"""
@spec with_stats(Ecto.Queryable.t(), Keyword.t() | nil) :: Ecto.Queryable.t()
def with_stats(query, options \\ []) do
Expand Down
14 changes: 13 additions & 1 deletion lib/accent/scopes/translations_count.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ defmodule Accent.Scopes.TranslationsCount do
query
|> count_translations(translations, exclude_empty_translations)
|> count_reviewed(translations)
|> count_translated(translations)

from(
[translations: t, reviewed: r] in query,
[translations: t, reviewed: r, translated: td] in query,
select_merge: %{
translations_count: coalesce(t.count, 0),
translated_count: coalesce(td.count, 0),
reviewed_count: coalesce(r.count, 0),
conflicts_count: coalesce(t.count, 0) - coalesce(r.count, 0)
}
Expand All @@ -59,4 +61,14 @@ defmodule Accent.Scopes.TranslationsCount do
reviewed = from(translations, where: [conflicted: false])
from(q in query, left_join: translations in subquery(reviewed), as: :reviewed, on: translations.field_id == q.id)
end

defp count_translated(query, translations) do
translated = from(translations, where: [translated: true])

from(q in query,
left_join: translations in subquery(translated),
as: :translated,
on: translations.field_id == q.id
)
end
end
1 change: 1 addition & 0 deletions lib/graphql/types/document.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule Accent.GraphQL.Types.Document do
field(:path, non_null(:string))
field(:format, non_null(:document_format))
field(:translations_count, non_null(:integer))
field(:translated_count, non_null(:integer))
field(:conflicts_count, non_null(:integer))
field(:reviewed_count, non_null(:integer))
end
Expand Down
1 change: 1 addition & 0 deletions lib/graphql/types/project.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ defmodule Accent.GraphQL.Types.Project do
field(:logo, :string)

field(:translations_count, non_null(:integer))
field(:translated_count, non_null(:integer))
field(:conflicts_count, non_null(:integer))
field(:reviewed_count, non_null(:integer))

Expand Down
Loading

0 comments on commit cfe1e9a

Please sign in to comment.