Skip to content

Commit

Permalink
[server] For GitLab projects without an owner avatar, fall back to th…
Browse files Browse the repository at this point in the history
…e namespace avatar, or generate the default GitLab avatar
  • Loading branch information
jankeromnes committed Mar 28, 2022
1 parent 8b9a40a commit 7e5c93e
Showing 1 changed file with 44 additions and 6 deletions.
50 changes: 44 additions & 6 deletions components/server/ee/src/gitlab/gitlab-app-support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ import { inject, injectable } from "inversify";
import { TokenProvider } from "../../../src/user/token-provider";
import { UserDB } from "@gitpod/gitpod-db/lib";
import { Gitlab } from "@gitbeaker/node";
import { ProjectSchemaDefault, NamespaceInfoSchemaDefault } from "@gitbeaker/core/dist/types/services/Projects";

// Add missing fields to Gitbeaker's ProjectSchema type
type ProjectSchema = ProjectSchemaDefault & {
last_activity_at: string;
namespace: NamespaceInfoSchemaDefault & {
avatar_url: string;
};
owner?: {
id: number;
name: string;
avatar_url: string;
};
};

@injectable()
export class GitLabAppSupport {
Expand Down Expand Up @@ -38,12 +52,12 @@ export class GitLabAppSupport {
//
const projectsWithAccess = await api.Projects.all({ min_access_level: "40", perPage: 100 });
for (const project of projectsWithAccess) {
const anyProject = project as any;
const path = anyProject.path as string;
const fullPath = anyProject.path_with_namespace as string;
const cloneUrl = anyProject.http_url_to_repo as string;
const updatedAt = anyProject.last_activity_at as string;
const accountAvatarUrl = anyProject.owner?.avatar_url as string;
const aProject = project as ProjectSchema;
const path = aProject.path as string;
const fullPath = aProject.path_with_namespace as string;
const cloneUrl = aProject.http_url_to_repo as string;
const updatedAt = aProject.last_activity_at as string;
const accountAvatarUrl = await this.getAccountAvatarUrl(aProject, params.provider.host);
const account = fullPath.split("/")[0];

(account === usersGitLabAccount ? ownersRepos : result).push({
Expand All @@ -61,4 +75,28 @@ export class GitLabAppSupport {
result.unshift(...ownersRepos);
return result;
}

protected async getAccountAvatarUrl(project: ProjectSchema, providerHost: string): Promise<string> {
const owner = project.owner || project.namespace;
if (owner.avatar_url) {
const url = owner.avatar_url;
// Sometimes GitLab avatar URLs are relative -- ensure we always use the correct host
return url[0] === "/" ? `https://${providerHost}${url}` : url;
}
// If there is no avatar, generate the same default avatar that GitLab uses. Based on:
// - https://gitlab.com/gitlab-org/gitlab/-/blob/b2a22b6e85200ce55ab09b5c765043441b086c96/app/helpers/avatars_helper.rb#L151-161
// - https://gitlab.com/gitlab-org/gitlab-foss/-/blob/84b4743475246e91dc78c3f25f9b335c40be84cd/app/assets/stylesheets/startup/startup-general.scss#L1611-1631
// - https://gitlab.com/gitlab-org/gitlab-foss/-/blob/84b4743475246e91dc78c3f25f9b335c40be84cd/app/assets/stylesheets/startup/startup-general.scss#L420-422
const text = owner.name[0].toUpperCase();
const backgroundColor = ["#fcf1ef", "#f4f0ff", "#f1f1ff", "#e9f3fc", "#ecf4ee", "#fdf1dd", "#f0f0f0"][
owner.id % 7
];
const svg =
`<svg viewBox="0 0 32 32" height="32" width="32" style="background-color: ${backgroundColor}" xmlns="http://www.w3.org/2000/svg">
<text x="50%" y="50%" style='font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"'>${text}</text>
</svg>`.replace(/\s+/g, " ");
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
}
}

0 comments on commit 7e5c93e

Please sign in to comment.