Skip to content
Snippets Groups Projects
Commit 7b8cbcdb authored by michael.minelli's avatar michael.minelli Committed by michael.minelli
Browse files

Move to Gitbeaker

parent 26d51c85
No related branches found
No related tags found
No related merge requests found
import GitlabVisibility from '../shared/types/Gitlab/GitlabVisibility';
import path from 'path';
import fs from 'fs';
import { Exercise } from '../types/DatabaseTypes';
import JSON5 from 'json5';
import GitlabVisibility from '../shared/types/Gitlab/GitlabVisibility';
type ConfigGitlabBadge = {
......@@ -52,13 +52,13 @@ class Config {
public readonly assignment: {
default: {
description: string; initReadme: boolean; sharedRunnersEnabled: boolean; visibility: string; wikiEnabled: boolean; template: string
description: string; initReadme: boolean; sharedRunnersEnabled: boolean; visibility: GitlabVisibility; wikiEnabled: boolean; template: string
}; baseFiles: Array<string>; filename: string
};
public readonly exercise: {
maxSameName: number; maxPerAssignment: number; resultsFolder: string, pipelineResultsFolder: string; default: {
description: string; visibility: string;
description: string; visibility: GitlabVisibility;
};
};
......@@ -116,7 +116,7 @@ class Config {
description : process.env.ASSIGNMENT_DEFAULT_DESCRIPTION?.convertWithEnvVars() ?? '',
initReadme : process.env.ASSIGNMENT_DEFAULT_INIT_README?.toBoolean() ?? false,
sharedRunnersEnabled: process.env.ASSIGNMENT_DEFAULT_SHARED_RUNNERS_ENABLED?.toBoolean() ?? true,
visibility : process.env.ASSIGNMENT_DEFAULT_VISIBILITY || GitlabVisibility.PRIVATE,
visibility : process.env.ASSIGNMENT_DEFAULT_VISIBILITY as GitlabVisibility || 'private',
wikiEnabled : process.env.ASSIGNMENT_DEFAULT_WIKI_ENABLED?.toBoolean() ?? false,
template : process.env.ASSIGNMENT_DEFAULT_TEMPLATE?.replace('{{USERNAME}}', this.gitlab.account.username).replace('{{TOKEN}}', this.gitlab.account.token) ?? ''
},
......@@ -131,7 +131,7 @@ class Config {
pipelineResultsFolder: process.env.EXERCISE_PIPELINE_RESULTS_FOLDER ?? '', //Do not use convertWithEnvVars() because it is used in the exercise creation and muste be interpreted at exercise runtime
default : {
description: process.env.EXERCISE_DEFAULT_DESCRIPTION?.convertWithEnvVars() ?? '',
visibility : process.env.EXERCISE_DEFAULT_VISIBILITY || GitlabVisibility.PRIVATE
visibility : process.env.EXERCISE_DEFAULT_VISIBILITY as GitlabVisibility || 'private'
}
};
}
......
import Config from '../config/Config';
import GitlabRelease from '../shared/types/Gitlab/GitlabRelease';
import GitlabManager from '../managers/GitlabManager';
import * as Gitlab from '@gitbeaker/rest';
class DojoCliVersionHelper {
......@@ -8,7 +8,7 @@ class DojoCliVersionHelper {
private latestVersion: string | undefined;
private async updateVersion(): Promise<void> {
const releases: Array<GitlabRelease> = await GitlabManager.getRepositoryReleases(Config.dojoCLI.repositoryId);
const releases: Array<Gitlab.ReleaseSchema> = await GitlabManager.getRepositoryReleases(Config.dojoCLI.repositoryId);
for ( const release of releases ) {
if ( !isNaN(+release.tag_name.replace('.', '')) ) {
this.latestVersion = release.tag_name;
......
import express from 'express';
import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
import logger from '../shared/logging/WinstonLogger';
import GitlabManager from '../managers/GitlabManager';
import { AxiosError } from 'axios';
import { StatusCodes } from 'http-status-codes';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import SharedGitlabManager from '../shared/managers/SharedGitlabManager';
import Config from '../config/Config';
import * as Gitlab from '@gitbeaker/rest';
class GlobalHelper {
async repositoryCreationError(message: string, error: unknown, req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: GitlabRepository): Promise<void> {
readonly sharedGitlabManager = new SharedGitlabManager(Config.gitlab.account.token);
async repositoryCreationError(message: string, error: unknown, req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: Gitlab.ProjectSchema): Promise<void> {
logger.error(message);
logger.error(error);
......
import { Prisma, UserRole } from '@prisma/client';
import LazyVal from '../../../shared/helpers/LazyVal';
import GitlabUser from '../../../shared/types/Gitlab/GitlabUser';
import GitlabManager from '../../../managers/GitlabManager';
import * as Gitlab from '@gitbeaker/rest';
export default Prisma.defineExtension(client => {
......@@ -26,7 +26,7 @@ export default Prisma.defineExtension(client => {
},
gitlabProfile : {
compute(user) {
return new LazyVal<GitlabUser | undefined>(() => GitlabManager.getUserById(user.id));
return new LazyVal<Gitlab.UserSchema | undefined>(() => GitlabManager.getUserById(user.id));
}
}
}
......
import axios from 'axios';
import Config from '../config/Config';
import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
import GitlabAccessLevel from '../shared/types/Gitlab/GitlabAccessLevel';
import GitlabMember from '../shared/types/Gitlab/GitlabMember';
import { StatusCodes } from 'http-status-codes';
import GitlabVisibility from '../shared/types/Gitlab/GitlabVisibility';
import GitlabUser from '../shared/types/Gitlab/GitlabUser';
import GitlabTreeFile from '../shared/types/Gitlab/GitlabTreeFile';
import parseLinkHeader from 'parse-link-header';
import GitlabFile from '../shared/types/Gitlab/GitlabFile';
import express from 'express';
import GitlabRoute from '../shared/types/Gitlab/GitlabRoute';
import SharedConfig from '../shared/config/SharedConfig';
import GitlabProfile from '../shared/types/Gitlab/GitlabProfile';
import GitlabRelease from '../shared/types/Gitlab/GitlabRelease';
import { CommitSchema, Gitlab } from '@gitbeaker/rest';
import { CommitSchema, ExpandedUserSchema, Gitlab, MemberSchema, ProjectBadgeSchema, ProjectSchema, ReleaseSchema, RepositoryFileExpandedSchema, RepositoryFileSchema, RepositoryTreeSchema, UserSchema } from '@gitbeaker/rest';
import logger from '../shared/logging/WinstonLogger';
import { AccessLevel, EditProjectOptions, ProjectVariableSchema, ProtectedBranchAccessLevel, ProtectedBranchSchema } from '@gitbeaker/core';
import axios from 'axios';
import parseLinkHeader from 'parse-link-header';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
class GitlabManager {
readonly api = new Gitlab({
private readonly api = new Gitlab({
host : SharedConfig.gitlab.URL,
token: Config.gitlab.account.token
});
private getApiUrl(route: GitlabRoute): string {
return `${ SharedConfig.gitlab.apiURL }${ route }`;
}
public async getUserProfile(token: string): Promise<GitlabProfile | undefined> {
public async getUserProfile(token: string): Promise<ExpandedUserSchema | undefined> {
try {
return (await axios.get<GitlabProfile>(this.getApiUrl(GitlabRoute.PROFILE_GET), {
headers: {
DojoOverrideAuthorization: true,
DojoAuthorizationHeader : 'Authorization',
DojoAuthorizationValue : `Bearer ${ token }`
}
})).data;
const profileApi = new Gitlab({
host : SharedConfig.gitlab.URL,
token: token
});
return await profileApi.Users.showCurrentUser();
} catch ( e ) {
return undefined;
}
}
public async getUserById(id: number): Promise<GitlabUser | undefined> {
public async getUserById(id: number): Promise<UserSchema | undefined> {
try {
const user = (await axios.get<GitlabUser>(`${ this.getApiUrl(GitlabRoute.USERS_GET) }/${ String(id) }`)).data;
const user = await this.api.Users.show(id);
return user.id === id ? user : undefined;
} catch ( e ) {
......@@ -53,34 +40,31 @@ class GitlabManager {
}
}
public async getUserByUsername(username: string): Promise<GitlabUser | undefined> {
public async getUserByUsername(username: string): Promise<UserSchema | undefined> {
try {
const params: Record<string, string> = {};
params['search'] = username;
const user = (await axios.get<Array<GitlabUser>>(this.getApiUrl(GitlabRoute.USERS_GET), { params: params })).data[0];
const user = await this.api.Users.all({
username: username,
maxPages: 1,
perPage : 1
});
return user.username === username ? user : undefined;
return user.length > 0 && user[0].username === username ? user[0] : undefined;
} catch ( e ) {
return undefined;
}
}
async getRepository(projectIdOrNamespace: string): Promise<GitlabRepository> {
const response = await axios.get<GitlabRepository>(this.getApiUrl(GitlabRoute.REPOSITORY_GET).replace('{{id}}', encodeURIComponent(projectIdOrNamespace)));
return response.data;
async getRepository(projectIdOrNamespace: string): Promise<ProjectSchema> {
return await this.api.Projects.show(projectIdOrNamespace);
}
async getRepositoryMembers(idOrNamespace: string): Promise<Array<GitlabMember>> {
const response = await axios.get<Array<GitlabMember>>(this.getApiUrl(GitlabRoute.REPOSITORY_MEMBERS_GET).replace('{{id}}', encodeURIComponent(idOrNamespace)));
return response.data;
async getRepositoryMembers(idOrNamespace: string): Promise<Array<MemberSchema>> {
return await this.api.ProjectMembers.all(idOrNamespace, { includeInherited: true });
}
async getRepositoryReleases(repoId: number): Promise<Array<GitlabRelease>> {
const response = await axios.get<Array<GitlabRelease>>(this.getApiUrl(GitlabRoute.REPOSITORY_RELEASES_GET).replace('{{id}}', String(repoId)));
return response.data;
async getRepositoryReleases(repoId: number): Promise<Array<ReleaseSchema>> {
return await this.api.ProjectReleases.all(repoId);
}
async getRepositoryLastCommit(repoId: number, branch: string = 'main'): Promise<CommitSchema | undefined> {
......@@ -98,86 +82,66 @@ class GitlabManager {
}
}
async createRepository(name: string, description: string, visibility: string, initializeWithReadme: boolean, namespace: number, sharedRunnersEnabled: boolean, wikiEnabled: boolean, importUrl: string): Promise<GitlabRepository> {
const response = await axios.post<GitlabRepository>(this.getApiUrl(GitlabRoute.REPOSITORY_CREATE), {
async createRepository(name: string, description: string, visibility: 'public' | 'internal' | 'private', initializeWithReadme: boolean, namespace: number, sharedRunnersEnabled: boolean, wikiEnabled: boolean, import_url: string): Promise<ProjectSchema> {
return await this.api.Projects.create({
name : name,
description : description,
import_url : importUrl,
initialize_with_readme: initializeWithReadme,
namespace_id : namespace,
shared_runners_enabled: sharedRunnersEnabled,
importUrl : import_url,
initializeWithReadme: initializeWithReadme,
namespaceId : namespace,
sharedRunnersEnabled: sharedRunnersEnabled,
visibility : visibility,
wiki_enabled : wikiEnabled
wikiAccessLevel : wikiEnabled ? 'enabled' : 'disabled'
});
return response.data;
}
deleteRepository(repoId: number): Promise<void> {
return axios.delete(this.getApiUrl(GitlabRoute.REPOSITORY_DELETE).replace('{{id}}', String(repoId)));
async deleteRepository(repoId: number): Promise<void> {
return await this.api.Projects.remove(repoId);
}
async forkRepository(forkId: number, name: string, path: string, description: string, visibility: string, namespace: number): Promise<GitlabRepository> {
const response = await axios.post<GitlabRepository>(this.getApiUrl(GitlabRoute.REPOSITORY_FORK).replace('{{id}}', String(forkId)), {
async forkRepository(forkId: number, name: string, path: string, description: string, visibility: 'public' | 'internal' | 'private', namespace: number): Promise<ProjectSchema> {
return await this.api.Projects.fork(forkId, {
name : name,
path : path,
description: description,
namespace_id: namespace,
namespaceId: namespace,
visibility : visibility
});
return response.data;
}
async editRepository(repoId: number, newAttributes: Partial<GitlabRepository>): Promise<GitlabRepository> {
const response = await axios.put<GitlabRepository>(this.getApiUrl(GitlabRoute.REPOSITORY_EDIT).replace('{{id}}', String(repoId)), newAttributes);
return response.data;
async editRepository(repoId: number, newAttributes: EditProjectOptions): Promise<ProjectSchema> {
return await this.api.Projects.edit(repoId, newAttributes);
}
changeRepositoryVisibility(repoId: number, visibility: GitlabVisibility): Promise<GitlabRepository> {
return this.editRepository(repoId, { visibility: visibility.toString() });
async changeRepositoryVisibility(repoId: number, visibility: GitlabVisibility): Promise<ProjectSchema> {
return await this.editRepository(repoId, { visibility: visibility });
}
async addRepositoryMember(repoId: number, userId: number, accessLevel: GitlabAccessLevel): Promise<GitlabMember> {
const response = await axios.post<GitlabMember>(this.getApiUrl(GitlabRoute.REPOSITORY_MEMBER_ADD).replace('{{id}}', String(repoId)), {
user_id : userId,
access_level: accessLevel
});
return response.data;
async addRepositoryMember(repoId: number, userId: number, accessLevel: Exclude<AccessLevel, AccessLevel.ADMIN>): Promise<MemberSchema> {
return await this.api.ProjectMembers.add(repoId, userId, accessLevel);
}
async addRepositoryVariable(repoId: number, key: string, value: string, isProtected: boolean, isMasked: boolean): Promise<GitlabMember> {
const response = await axios.post<GitlabMember>(this.getApiUrl(GitlabRoute.REPOSITORY_VARIABLES_ADD).replace('{{id}}', String(repoId)), {
key : key,
variable_type: 'env_var',
value : value,
async addRepositoryVariable(repoId: number, key: string, value: string, isProtected: boolean, isMasked: boolean): Promise<ProjectVariableSchema> {
return await this.api.ProjectVariables.create(repoId, key, value, {
variableType: 'env_var',
protected : isProtected,
masked : isMasked
});
return response.data;
}
async addRepositoryBadge(repoId: number, linkUrl: string, imageUrl: string, name: string): Promise<GitlabMember> {
const response = await axios.post<GitlabMember>(this.getApiUrl(GitlabRoute.REPOSITORY_BADGES_ADD).replace('{{id}}', String(repoId)), {
link_url : linkUrl,
image_url: imageUrl,
async addRepositoryBadge(repoId: number, linkUrl: string, imageUrl: string, name: string): Promise<ProjectBadgeSchema> {
return await this.api.ProjectBadges.add(repoId, linkUrl, imageUrl, {
name: name
});
return response.data;
}
async checkTemplateAccess(projectIdOrNamespace: string, req: express.Request, res?: express.Response): Promise<boolean> {
// Get the Gitlab project and check if it have public or internal visibility
try {
const project: GitlabRepository = await this.getRepository(projectIdOrNamespace);
const project: ProjectSchema = await this.getRepository(projectIdOrNamespace);
if ( [ GitlabVisibility.PUBLIC.valueOf(), GitlabVisibility.INTERNAL.valueOf() ].includes(project.visibility) ) {
req.session.sendResponse(res, StatusCodes.OK);
return true;
if ( [ 'public', 'internal' ].includes(project.visibility) ) {
return StatusCodes.OK;
}
} catch ( e ) {
req.session.sendResponse(res, StatusCodes.NOT_FOUND, undefined, 'Template not found', DojoStatusCode.GITLAB_TEMPLATE_NOT_FOUND);
......@@ -191,7 +155,7 @@ class GitlabManager {
dojo: false
};
members.forEach(member => {
if ( member.access_level >= GitlabAccessLevel.REPORTER ) {
if ( member.access_level >= AccessLevel.REPORTER ) {
if ( member.id === req.session.profile.id ) {
isUsersAtLeastReporter.user = true;
} else if ( member.id === Config.gitlab.account.id ) {
......@@ -209,91 +173,49 @@ class GitlabManager {
}
}
async protectBranch(repoId: number, branchName: string, allowForcePush: boolean, allowedToMerge: GitlabAccessLevel, allowedToPush: GitlabAccessLevel, allowedToUnprotect: GitlabAccessLevel): Promise<GitlabMember> {
const response = await axios.post<GitlabMember>(this.getApiUrl(GitlabRoute.REPOSITORY_BRANCHES_PROTECT).replace('{{id}}', String(repoId)), {
name : branchName,
allow_force_push : allowForcePush,
merge_access_level : allowedToMerge.valueOf(),
push_access_level : allowedToPush.valueOf(),
unprotect_access_level: allowedToUnprotect.valueOf()
async protectBranch(repoId: number, branchName: string, allowForcePush: boolean, allowedToMerge: ProtectedBranchAccessLevel, allowedToPush: ProtectedBranchAccessLevel, allowedToUnprotect: ProtectedBranchAccessLevel): Promise<ProtectedBranchSchema> {
return await this.api.ProtectedBranches.protect(repoId, branchName, {
allowForcePush : allowForcePush,
mergeAccessLevel : allowedToMerge,
pushAccessLevel : allowedToPush,
unprotectAccessLevel: allowedToUnprotect
});
return response.data;
}
async getRepositoryTree(repoId: number, recursive: boolean = true, branch: string = 'main'): Promise<Array<GitlabTreeFile>> {
const address: string | undefined = this.getApiUrl(GitlabRoute.REPOSITORY_TREE).replace('{{id}}', String(repoId));
let params: Partial<parseLinkHeader.Link | { recursive: boolean, per_page: number }> | undefined = {
pagination: 'keyset',
async getRepositoryTree(repoId: number, recursive: boolean = true, branch: string = 'main'): Promise<Array<RepositoryTreeSchema>> {
return await this.api.Repositories.allRepositoryTrees(repoId, {
recursive: recursive,
per_page : 100,
ref : branch
};
const results: Array<GitlabTreeFile> = [];
while ( params !== undefined ) {
const response = await axios.get<Array<GitlabTreeFile>>(address, {
params: params
});
results.push(...response.data);
if ( 'link' in response.headers ) {
params = parseLinkHeader(response.headers['link'])?.next ?? undefined;
} else {
params = undefined;
}
}
return results;
}
private getRepositoryFileUrl(repoId: number, filePath: string): string {
return this.getApiUrl(GitlabRoute.REPOSITORY_FILE).replace('{{id}}', String(repoId)).replace('{{filePath}}', encodeURIComponent(filePath));
async getFile(repoId: number, filePath: string, branch: string = 'main'): Promise<RepositoryFileExpandedSchema> {
return await this.api.RepositoryFiles.show(repoId, filePath, branch);
}
async getFile(repoId: number, filePath: string, branch: string = 'main'): Promise<GitlabFile> {
const response = await axios.get<GitlabFile>(this.getRepositoryFileUrl(repoId, filePath), {
params: {
ref: branch
}
});
private async createUpdateFile(create: boolean, repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined): Promise<RepositoryFileSchema> {
const gitFunction = create ? this.api.RepositoryFiles.create : this.api.RepositoryFiles.edit;
return response.data;
}
private async createUpdateFile(create: boolean, repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined) {
const axiosFunction = create ? axios.post : axios.put;
await axiosFunction(this.getRepositoryFileUrl(repoId, filePath), {
return await gitFunction(repoId, filePath, branch, fileBase64, commitMessage, {
encoding : 'base64',
branch : branch,
commit_message: commitMessage,
content : fileBase64,
author_name : authorName,
author_email : authorMail
authorName : authorName,
authorEmail: authorMail
});
}
async createFile(repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined) {
async createFile(repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined): Promise<RepositoryFileSchema> {
return this.createUpdateFile(true, repoId, filePath, fileBase64, commitMessage, branch, authorName, authorMail);
}
async updateFile(repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined) {
async updateFile(repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined): Promise<RepositoryFileSchema> {
return this.createUpdateFile(false, repoId, filePath, fileBase64, commitMessage, branch, authorName, authorMail);
}
async deleteFile(repoId: number, filePath: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined) {
await axios.delete(this.getRepositoryFileUrl(repoId, filePath), {
data: {
branch : branch,
commit_message: commitMessage,
author_name : authorName,
author_email : authorMail
}
async deleteFile(repoId: number, filePath: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined): Promise<void> {
await this.api.RepositoryFiles.remove(repoId, filePath, branch, commitMessage, {
authorName : authorName,
authorEmail: authorMail
});
}
}
......
import axios, { AxiosError, AxiosRequestHeaders } from 'axios';
import Config from '../config/Config';
import FormData from 'form-data';
import logger from '../shared/logging/WinstonLogger';
import SharedConfig from '../shared/config/SharedConfig';
class HttpManager {
......@@ -16,19 +14,6 @@ class HttpManager {
if ( config.data instanceof FormData ) {
config.headers = { ...config.headers, ...(config.data as FormData).getHeaders() } as AxiosRequestHeaders;
}
if ( config.url && config.url.indexOf(SharedConfig.gitlab.apiURL) !== -1 && !config.headers.DojoOverrideAuthorization ) {
config.headers['PRIVATE-TOKEN'] = Config.gitlab.account.token;
}
if ( config.headers.DojoOverrideAuthorization && 'DojoAuthorizationHeader' in config.headers && 'DojoAuthorizationValue' in config.headers ) {
config.headers[config.headers.DojoAuthorizationHeader] = config.headers.DojoAuthorizationValue;
delete config.headers.DojoOverrideAuthorization;
delete config.headers.DojoAuthorizationHeader;
delete config.headers.DojoAuthorizationValue;
}
return config;
});
}
......
import GitlabUser from '../shared/types/Gitlab/GitlabUser';
import { Prisma } from '@prisma/client';
import db from '../helpers/DatabaseHelper';
import GitlabProfile from '../shared/types/Gitlab/GitlabProfile';
import { User } from '../types/DatabaseTypes';
import * as Gitlab from '@gitbeaker/rest';
class UserManager {
......@@ -24,7 +23,7 @@ class UserManager {
}) as unknown as User ?? undefined;
}
async getUpdateFromGitlabProfile(gitlabProfile: GitlabProfile): Promise<User> {
async getUpdateFromGitlabProfile(gitlabProfile: Gitlab.ExpandedUserSchema): Promise<User> {
await db.user.upsert({
where : {
id: gitlabProfile.id
......@@ -46,7 +45,7 @@ class UserManager {
return (await this.getById(gitlabProfile.id))!;
}
async getFromGitlabUser(gitlabUser: GitlabUser, createIfNotExist: boolean = false, include: Prisma.UserInclude | undefined = undefined): Promise<User | number | undefined> {
async getFromGitlabUser(gitlabUser: Gitlab.UserSchema, createIfNotExist: boolean = false, include: Prisma.UserInclude | undefined = undefined): Promise<User | number | undefined> {
let user = await this.getById(gitlabUser.id, include) ?? gitlabUser.id;
if ( typeof user === 'number' && createIfNotExist ) {
......@@ -61,7 +60,7 @@ class UserManager {
return user;
}
async getFromGitlabUsers(gitlabUsers: Array<GitlabUser>, createIfNotExist: boolean = false, include: Prisma.UserInclude | undefined = undefined): Promise<Array<User | number | undefined>> {
async getFromGitlabUsers(gitlabUsers: Array<Gitlab.UserSchema>, createIfNotExist: boolean = false, include: Prisma.UserInclude | undefined = undefined): Promise<Array<User | number | undefined>> {
return Promise.all(gitlabUsers.map(gitlabUser => this.getFromGitlabUser(gitlabUser, createIfNotExist, include)));
}
}
......
......@@ -6,12 +6,8 @@ import RoutesManager from '../express/RoutesManager';
import ParamsValidatorMiddleware from '../middlewares/ParamsValidatorMiddleware';
import SecurityMiddleware from '../middlewares/SecurityMiddleware';
import SecurityCheckType from '../types/SecurityCheckType';
import GitlabUser from '../shared/types/Gitlab/GitlabUser';
import GitlabManager from '../managers/GitlabManager';
import Config from '../config/Config';
import GitlabMember from '../shared/types/Gitlab/GitlabMember';
import GitlabAccessLevel from '../shared/types/Gitlab/GitlabAccessLevel';
import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
import { AxiosError, HttpStatusCode } from 'axios';
import logger from '../shared/logging/WinstonLogger';
import DojoValidators from '../helpers/DojoValidators';
......@@ -19,13 +15,13 @@ import { Prisma } from '@prisma/client';
import db from '../helpers/DatabaseHelper';
import { Assignment } from '../types/DatabaseTypes';
import AssignmentManager from '../managers/AssignmentManager';
import GitlabVisibility from '../shared/types/Gitlab/GitlabVisibility';
import fs from 'fs';
import path from 'path';
import SharedAssignmentHelper from '../shared/helpers/Dojo/SharedAssignmentHelper';
import GlobalHelper from '../helpers/GlobalHelper';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import DojoModelsHelper from '../helpers/DojoModelsHelper';
import * as Gitlab from '@gitbeaker/rest';
class AssignmentRoutes implements RoutesManager {
......@@ -84,13 +80,13 @@ class AssignmentRoutes implements RoutesManager {
private async createAssignment(req: express.Request, res: express.Response) {
const params: {
name: string, members: Array<GitlabUser>, template: string
name: string, members: Array<Gitlab.UserSchema>, template: string
} = req.body;
params.members = [ await req.session.profile.gitlabProfile.value, ...params.members ];
params.members = params.members.removeObjectDuplicates(gitlabUser => gitlabUser.id);
let repository: GitlabRepository;
let repository: Gitlab.ProjectSchema;
try {
repository = await GitlabManager.createRepository(params.name, Config.assignment.default.description.replace('{{ASSIGNMENT_NAME}}', params.name), Config.assignment.default.visibility, Config.assignment.default.initReadme, Config.gitlab.group.assignments, Config.assignment.default.sharedRunnersEnabled, Config.assignment.default.wikiEnabled, params.template);
} catch ( error ) {
......@@ -111,7 +107,7 @@ class AssignmentRoutes implements RoutesManager {
await new Promise(resolve => setTimeout(resolve, Config.gitlab.repository.timeoutAfterCreation));
try {
await GitlabManager.protectBranch(repository.id, '*', true, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER);
await GitlabManager.protectBranch(repository.id, '*', true, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.ADMIN);
await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status');
} catch ( error ) {
......@@ -129,9 +125,9 @@ class AssignmentRoutes implements RoutesManager {
}
try {
await Promise.all(params.members.map(member => member.id).map(async (memberId: number): Promise<GitlabMember | false> => {
await Promise.all(params.members.map(member => member.id).map(async (memberId: number): Promise<Gitlab.MemberSchema | false> => {
try {
return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.DEVELOPER);
return await GitlabManager.addRepositoryMember(repository.id, memberId, Gitlab.AccessLevel.DEVELOPER);
} catch ( error ) {
logger.error('Add member error');
logger.error(error);
......@@ -180,7 +176,7 @@ class AssignmentRoutes implements RoutesManager {
}
try {
await GitlabManager.changeRepositoryVisibility(req.boundParams.assignment!.gitlabId, publish ? GitlabVisibility.INTERNAL : GitlabVisibility.PRIVATE);
await GitlabManager.changeRepositoryVisibility(req.boundParams.assignment!.gitlabId, publish ? 'internal' : 'private');
await db.assignment.update({
where: {
......
......@@ -5,23 +5,16 @@ import { StatusCodes } from 'http-status-codes';
import RoutesManager from '../express/RoutesManager';
import ParamsValidatorMiddleware from '../middlewares/ParamsValidatorMiddleware';
import SecurityMiddleware from '../middlewares/SecurityMiddleware';
import GitlabUser from '../shared/types/Gitlab/GitlabUser';
import GitlabManager from '../managers/GitlabManager';
import Config from '../config/Config';
import GitlabRepository from '../shared/types/Gitlab/GitlabRepository';
import { AxiosError } from 'axios';
import logger from '../shared/logging/WinstonLogger';
import DojoValidators from '../helpers/DojoValidators';
import { v4 as uuidv4 } from 'uuid';
import GitlabMember from '../shared/types/Gitlab/GitlabMember';
import GitlabAccessLevel from '../shared/types/Gitlab/GitlabAccessLevel';
import { Prisma } from '@prisma/client';
import { Assignment, Exercise } from '../types/DatabaseTypes';
import db from '../helpers/DatabaseHelper';
import SecurityCheckType from '../types/SecurityCheckType';
import GitlabTreeFile from '../shared/types/Gitlab/GitlabTreeFile';
import GitlabFile from '../shared/types/Gitlab/GitlabFile';
import GitlabTreeFileType from '../shared/types/Gitlab/GitlabTreeFileType';
import JSON5 from 'json5';
import fs from 'fs';
import path from 'path';
......@@ -31,6 +24,8 @@ import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import GlobalHelper from '../helpers/GlobalHelper';
import { IFileDirStat } from '../shared/helpers/recursiveFilesStats/RecursiveFilesStats';
import ExerciseManager from '../managers/ExerciseManager';
import * as Gitlab from '@gitbeaker/rest';
import GitlabTreeFileType from '../shared/types/Gitlab/GitlabTreeFileType';
class ExerciseRoutes implements RoutesManager {
......@@ -77,19 +72,19 @@ class ExerciseRoutes implements RoutesManager {
backend.post('/exercises/:exerciseIdOrUrl/results', SecurityMiddleware.check(false, SecurityCheckType.EXERCISE_SECRET), ParamsValidatorMiddleware.validate(this.resultValidator), this.createResult.bind(this));
}
private getExerciseName(assignment: Assignment, members: Array<GitlabUser>, suffix: number): string {
private getExerciseName(assignment: Assignment, members: Array<Gitlab.UserSchema>, suffix: number): string {
const memberNames: string = members.map(member => member.username).sort((a, b) => a.localeCompare(b)).join(' + ');
const suffixString: string = suffix > 0 ? ` - ${ suffix }` : '';
return `DojoEx - ${ assignment.name } - ${ memberNames }${ suffixString }`;
}
private getExercisePath(assignment: Assignment, exerciseId: string): string {
return `dojo-ex_${ (assignment.gitlabLastInfo as unknown as GitlabRepository).path }_${ exerciseId }`;
return `dojo-ex_${ (assignment.gitlabLastInfo as unknown as Gitlab.ProjectSchema).path }_${ exerciseId }`;
}
private async checkExerciseLimit(assignment: Assignment, members: Array<GitlabUser>): Promise<Array<GitlabUser>> {
const exercises: Array<Exercise> = await ExerciseManager.getFromAssignment(assignment.name, { members: true });
const reachedLimitUsers: Array<GitlabUser> = [];
private async checkExerciseLimit(assignment: Assignment, members: Array<Gitlab.UserSchema>): Promise<Array<Gitlab.UserSchema>> {
const exercises: Array<Exercise> | undefined = await ExerciseManager.getFromAssignment(assignment.name, { members: true });
const reachedLimitUsers: Array<Gitlab.UserSchema> = [];
if ( exercises.length > 0 ) {
for ( const member of members ) {
const exerciseCount: number = exercises.filter(exercise => exercise.members.findIndex(exerciseMember => exerciseMember.id === member.id) !== -1).length;
......@@ -102,13 +97,13 @@ class ExerciseRoutes implements RoutesManager {
return reachedLimitUsers;
}
private async createExerciseRepository(assignment: Assignment, members: Array<GitlabUser>, exerciseId: string, req: express.Request, res: express.Response): Promise<GitlabRepository | undefined> {
let repository!: GitlabRepository;
private async createExerciseRepository(assignment: Assignment, members: Array<Gitlab.UserSchema>, exerciseId: string, req: express.Request, res: express.Response): Promise<Gitlab.ProjectSchema | undefined> {
let repository!: Gitlab.ProjectSchema;
let suffix: number = 0;
do {
try {
repository = await GitlabManager.forkRepository((assignment.gitlabCreationInfo as unknown as GitlabRepository).id, this.getExerciseName(assignment, members, suffix), this.getExercisePath(req.boundParams.assignment!, exerciseId), Config.exercise.default.description.replace('{{ASSIGNMENT_NAME}}', assignment.name), Config.exercise.default.visibility, Config.gitlab.group.exercises);
repository = await GitlabManager.forkRepository((assignment.gitlabCreationInfo as unknown as Gitlab.ProjectSchema).id, this.getExerciseName(assignment, params.members, suffix), this.getExercisePath(req.boundParams.assignment!, exerciseId), Config.exercise.default.description.replace('{{ASSIGNMENT_NAME}}', assignment.name), Config.exercise.default.visibility, Config.gitlab.group.exercises);
break;
} catch ( error ) {
logger.error('Repo creation error');
......@@ -161,7 +156,7 @@ class ExerciseRoutes implements RoutesManager {
await new Promise(resolve => setTimeout(resolve, Config.gitlab.repository.timeoutAfterCreation));
try {
await GitlabManager.protectBranch(repository.id, '*', false, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER);
await GitlabManager.protectBranch(repository.id, '*', false, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.DEVELOPER, Gitlab.AccessLevel.ADMIN);
await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_EXERCISE_ID', exerciseId, false, true);
await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_SECRET', secret, false, true);
......@@ -181,9 +176,9 @@ class ExerciseRoutes implements RoutesManager {
}
try {
await Promise.all([ ...new Set([ ...assignment.staff.map(user => user.id), ...params.members.map(member => member.id) ]) ].map(async (memberId: number): Promise<GitlabMember | false> => {
await Promise.all([ ...new Set([ ...assignment.staff.map(user => user.id), ...params.members.map(member => member.id) ]) ].map(async (memberId: number): Promise<Gitlab.MemberSchema | false> => {
try {
return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.DEVELOPER);
return await GitlabManager.addRepositoryMember(repository.id, memberId, Gitlab.AccessLevel.DEVELOPER);
} catch ( error ) {
logger.error('Add member error');
logger.error(error);
......@@ -227,10 +222,10 @@ class ExerciseRoutes implements RoutesManager {
}
private async getAssignment(req: express.Request, res: express.Response) {
const repoTree: Array<GitlabTreeFile> = await GitlabManager.getRepositoryTree(req.boundParams.exercise!.assignment.gitlabId);
const repoTree: Array<Gitlab.RepositoryTreeSchema> = await GitlabManager.getRepositoryTree(req.boundParams.exercise!.assignment.gitlabId);
let assignmentHjsonFile!: GitlabFile;
const immutableFiles: Array<GitlabFile> = await Promise.all(Config.assignment.baseFiles.map(async (baseFile: string) => {
let assignmentHjsonFile!: Gitlab.RepositoryFileExpandedSchema;
const immutableFiles: Array<Gitlab.RepositoryFileExpandedSchema> = await Promise.all(Config.assignment.baseFiles.map(async (baseFile: string) => {
const file = await GitlabManager.getFile(req.boundParams.exercise!.assignment.gitlabId, baseFile);
if ( baseFile === Config.assignment.filename ) {
......
......@@ -8,8 +8,8 @@ import SecurityMiddleware from '../middlewares/SecurityMiddleware';
import GitlabManager from '../managers/GitlabManager';
import UserManager from '../managers/UserManager';
import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode';
import SharedGitlabManager from '../shared/managers/SharedGitlabManager';
import Config from '../config/Config';
import GlobalHelper from '../helpers/GlobalHelper';
class SessionRoutes implements RoutesManager {
......@@ -64,7 +64,7 @@ class SessionRoutes implements RoutesManager {
refreshToken: string
} = req.body;
const gitlabTokens = await SharedGitlabManager.getTokens(params.refreshToken, true, Config.login.gitlab.client.secret);
const gitlabTokens = await GlobalHelper.sharedGitlabManager.getTokens(params.refreshToken, true, Config.login.gitlab.client.secret);
req.session.sendResponse(res, StatusCodes.OK, gitlabTokens);
} catch ( error ) {
......
Subproject commit 985c0b6a5dcb640404e5cf5fc91978215f961e3b
Subproject commit 47b289f99ef88df993f5977efa6a53e4bd0abe85
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment