refactor(repository): move magic/duplicated strings into constants file@@ -4,6 +4,8 @@ import type { AppThemeScheme } from "./types";
type Const = {
APP_NAME: string;
+ PRIMARY_BRANCH_REF: string;
+ DEFAULT_HEAD_REF: string;
DEFAULT_THEME_SCHEME: AppThemeScheme;
README_FILE_NAMES: string[];
SESSION_TTL_SECONDS: number;
@@ -12,6 +14,8 @@ type Const = {
export const Const: Const = {
APP_NAME: "GitFOSS",
+ PRIMARY_BRANCH_REF: "main",
+ DEFAULT_HEAD_REF: "HEAD",
DEFAULT_THEME_SCHEME: "dark",
README_FILE_NAMES: [
"READ_ME",
@@ -20,7 +20,7 @@ import RepositoryDetailsView, {
const getRepositoryBrowserView: ReqHandler = async (request, reply) => {
const params =
request.params as AppRoutesParams[AppRoute.REPOSITORY_BROWSER]["params"];
- const { orgSlug, repoSlug, ref } = params;
+ const { orgSlug, repoSlug, currentRef } = params;
const path = params["*"];
const orgService = makeOrganizationService({ request });
@@ -57,7 +57,9 @@ const getRepositoryBrowserView: ReqHandler = async (request, reply) => {
repo,
path,
Const.README_FILE_NAMES,
- ref === "main" ? "HEAD" : ref
+ currentRef === Const.PRIMARY_BRANCH_REF
+ ? Const.DEFAULT_HEAD_REF
+ : currentRef
);
const readmeFileContent =
@@ -65,14 +67,16 @@ const getRepositoryBrowserView: ReqHandler = async (request, reply) => {
? await repoService.getRepositoryFileContent(
repo,
`${path}${readmeFiles[0]}`,
- ref === "main" ? "HEAD" : ref
+ currentRef === Const.PRIMARY_BRANCH_REF
+ ? Const.DEFAULT_HEAD_REF
+ : currentRef
)
: null;
const commitLogs = await repoService.getRepositoryCommitLog(
repo,
path,
- ref,
+ currentRef,
true
);
@@ -83,7 +87,7 @@ const getRepositoryBrowserView: ReqHandler = async (request, reply) => {
return reqHandler<RepositoryDetailsViewProps>(RepositoryDetailsView.name, {
branches,
- currentRef: ref,
+ currentRef,
currentUser,
cloneUrl: {
http: await repoService.getRepositoryHTTPCloneUrl(repo),
@@ -94,8 +98,8 @@ const getRepositoryBrowserView: ReqHandler = async (request, reply) => {
path,
readmeFileContent,
repo,
- repoHead: await repoService.getRepositoryHead(repo, ref),
- repoFiles: await repoService.getRepositoryFiles(repo, path, ref),
+ repoHead: await repoService.getRepositoryHead(repo, currentRef),
+ repoFiles: await repoService.getRepositoryFiles(repo, path, currentRef),
tags,
});
}
@@ -106,8 +110,8 @@ const getRepositoryBrowserView: ReqHandler = async (request, reply) => {
let fileContent =
linguistInfos.type === "image"
- ? await repoService.getRepositoryFileContentBase64(repo, path, ref)
- : await repoService.getRepositoryFileContent(repo, path, ref);
+ ? await repoService.getRepositoryFileContentBase64(repo, path, currentRef)
+ : await repoService.getRepositoryFileContent(repo, path, currentRef);
if (fileContent == null) {
return reply.status(404).callNotFound();
@@ -119,7 +123,7 @@ const getRepositoryBrowserView: ReqHandler = async (request, reply) => {
);
return reqHandler<RepositoryBrowserViewProps>(RepositoryBrowserView.name, {
- currentRef: ref,
+ currentRef,
currentUser,
fileContent,
linguistInfos,
@@ -13,8 +13,8 @@ import RepositoryCommitsLogView, {
} from "../../views/repository/RepositoryCommitsLogView";
const getRepositoryCommitsLogView: ReqHandler = async (request, reply) => {
- const { orgSlug, repoSlug } =
- request.params as AppRoutesParams[AppRoute.REPOSITORY_BROWSER]["params"];
+ const { orgSlug, repoSlug, currentRef } =
+ request.params as AppRoutesParams[AppRoute.REPOSITORY_COMMITS_LOG]["params"];
const orgService = makeOrganizationService({ request });
const repoService = makeRepositoryService({ request });
@@ -49,6 +49,7 @@ const getRepositoryCommitsLogView: ReqHandler = async (request, reply) => {
return reqHandler<RepositoryCommitsLogViewProps>(
RepositoryCommitsLogView.name,
{
+ currentRef,
parentOrg,
repo,
history,
@@ -32,7 +32,7 @@ const getRepositoryDetailsView: ReqHandler = async (request, reply) => {
: null;
const path = "/";
- const ref = "HEAD";
+ const currentRef = Const.DEFAULT_HEAD_REF;
const parentOrg = (await orgService.getOrganizationBySlug(orgSlug, {
memberships: true,
@@ -69,7 +69,7 @@ const getRepositoryDetailsView: ReqHandler = async (request, reply) => {
const commitLogs = await repoService.getRepositoryCommitLog(
repo,
"",
- ref,
+ currentRef,
true
);
@@ -83,7 +83,7 @@ const getRepositoryDetailsView: ReqHandler = async (request, reply) => {
try {
return reqHandler<RepositoryDetailsViewProps>(RepositoryDetailsView.name, {
branches,
- currentRef: ref,
+ currentRef,
currentUser,
cloneUrl: {
http: await repoService.getRepositoryHTTPCloneUrl(repo),
@@ -94,18 +94,18 @@ const getRepositoryDetailsView: ReqHandler = async (request, reply) => {
path,
readmeFileContent,
repo,
- repoHead: await repoService.getRepositoryHead(repo, ref),
- repoFiles: await repoService.getRepositoryFiles(repo, "", ref),
+ repoHead: await repoService.getRepositoryHead(repo, currentRef),
+ repoFiles: await repoService.getRepositoryFiles(repo, "", currentRef),
tags,
});
} catch (err) {
const error = err as Error;
- if (error.message.includes("Not a valid object name HEAD")) {
+ if (error.message.includes(`${currentRef} is not a valid object name`)) {
return reqHandler<RepositoryDetailsViewProps>(
RepositoryDetailsView.name,
{
branches,
- currentRef: ref,
+ currentRef,
currentUser,
cloneUrl: {
http: await repoService.getRepositoryHTTPCloneUrl(repo),
@@ -1,11 +1,13 @@
// 1st-party
import type { ReqHandler } from "@ethicdevs/react-monolith";
+import { ResourceVisibility } from "@prisma/client";
// app
import { AppRoute, AppRoutesParams } from "../../routes";
// app services
import { makeOrganizationService } from "../../services/organization";
import { makePullRequestService } from "../../services/pullRequest";
import { makeRepositoryService } from "../../services/repository";
+import { makeUsersService } from "../../services/user";
// app views
import RepositoryPullRequestsView, {
RepositoryPullRequestsViewProps,
@@ -18,6 +20,13 @@ const getRepositoryPullRequestsView: ReqHandler = async (request, reply) => {
const orgService = makeOrganizationService({ request });
const prService = makePullRequestService({ request });
const repoService = makeRepositoryService({ request });
+ const usersService = makeUsersService({ request });
+
+ const currentUser =
+ request.session.data.authenticated &&
+ request.session.data.curr_user_uid != null
+ ? await usersService.getUserById(request.session.data.curr_user_uid)
+ : null;
const parentOrg = await orgService.getOrganizationBySlug(orgSlug);
@@ -31,6 +40,16 @@ const getRepositoryPullRequestsView: ReqHandler = async (request, reply) => {
return reply.status(404).callNotFound();
}
+ if (repo.visibility === ResourceVisibility.PRIVATE) {
+ if (currentUser == null) {
+ return reply.status(404).callNotFound();
+ } else if (
+ (await repoService.canUserAccessRepository(currentUser, repo)) === false
+ ) {
+ return reply.status(404).callNotFound();
+ }
+ }
+
const pullRequests = await prService.getPullRequestsInRepository(repo);
const reqHandler = reply.makeRequestHandler(request, reply);
@@ -7,9 +7,10 @@ import type { RepositoryObject } from "../types";
import { Grid } from "../components/Grid";
export interface RepositoryCommitSummaryLineProps {
+ commit: RepositoryObject;
+ currentRef: string;
orgSlug: string;
repoSlug: string;
- commit: RepositoryObject;
}
const MAX_COMMIT_LINE_LENGTH = 60;
@@ -8,6 +8,7 @@ import type {
RepositoryFileDiffChunk,
WithThemeSchemeProp,
} from "../types";
+import { Const } from "../const";
import { Card, Grid } from "../components";
// app islands
import Code, { getThemedCodeCss } from "../islands/Code";
@@ -63,10 +64,10 @@ const RepositoryFilesDiffsList: ReactIsland<
View file (current ref)
</a>
<a
- href={`/${orgSlug}/${repoSlug}/main/tree/${diff.to}`}
+ href={`/${orgSlug}/${repoSlug}/${Const.PRIMARY_BRANCH_REF}/tree/${diff.to}`}
style={{ marginLeft: 16 }}
>
- View file (main)
+ View file (${Const.PRIMARY_BRANCH_REF})
</a>
</div>
</Grid.Row>
@@ -77,6 +77,7 @@ export interface AppRoutesParams extends IRouteParams {
params: {
orgSlug: string;
repoSlug: string;
+ currentRef: string;
};
};
[AppRoute.REPOSITORY_COMPARE]: {
@@ -107,13 +108,14 @@ export interface AppRoutesParams extends IRouteParams {
params: {
orgSlug: string;
repoSlug: string;
+ currentRef: string;
};
};
[AppRoute.REPOSITORY_BROWSER]: {
params: {
orgSlug: string;
repoSlug: string;
- ref: string;
+ currentRef: string;
"*": string;
};
};
@@ -202,7 +204,7 @@ export const AppRoutesSchemas: Record<AppRoute, undefined | FastifySchema> = {
[AppRoute.REPOSITORY_COMMITS_LOG]: {
params: {
type: "object",
- required: ["orgSlug", "repoSlug"],
+ required: ["orgSlug", "repoSlug", "currentRef"],
additionalProperties: false,
properties: {
orgSlug: {
@@ -211,6 +213,9 @@ export const AppRoutesSchemas: Record<AppRoute, undefined | FastifySchema> = {
repoSlug: {
type: "string",
},
+ currentRef: {
+ type: "string"
+ },
},
},
},
@@ -318,7 +323,7 @@ export const AppRoutesSchemas: Record<AppRoute, undefined | FastifySchema> = {
[AppRoute.REPOSITORY_BROWSER]: {
params: {
type: "object",
- required: ["orgSlug", "repoSlug", "ref", "*"],
+ required: ["orgSlug", "repoSlug", "currentRef", "*"],
additionalProperties: false,
properties: {
orgSlug: {
@@ -327,7 +332,7 @@ export const AppRoutesSchemas: Record<AppRoute, undefined | FastifySchema> = {
repoSlug: {
type: "string",
},
- ref: {
+ currentRef: {
type: "string",
},
"*": {
@@ -465,7 +470,7 @@ const RootAppRouter: AppRouter = () => {
<Router.Route
name={AppRoute.REPOSITORY_COMMITS_LOG}
method={"GET"}
- path={"/:orgSlug/:repoSlug/commits"} // TODO: add :ref before /commits + adaptations to links
+ path={"/:orgSlug/:repoSlug/:ref/commits"}
schema={AppRoutesSchemas[AppRoute.REPOSITORY_COMMITS_LOG]}
handler={RepositoryController.getRepositoryCommitsLogView}
/>
@@ -1,13 +1,15 @@
// std
import { existsSync } from "node:fs";
+import { mkdir } from "node:fs/promises";
import { spawn } from "node:child_process";
// 1st-party
import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// generated via script[generate:prisma]
import type { Repository } from "@prisma/client";
+// app
+import { Const } from "../../const";
// service
import type { CreateRepositoryDTO, RepositoryServiceDeps } from "./types";
-import { mkdir } from "node:fs/promises";
const makeCreateRepository: ServiceMethodFactory<
RepositoryServiceDeps,
@@ -69,7 +71,7 @@ const makeCreateRepository: ServiceMethodFactory<
[
"init",
"--bare",
- "--initial-branch=main",
+ `--initial-branch=${Const.PRIMARY_BRANCH_REF}`,
"--shared=group",
`${newRepo.slug}.git`,
],
@@ -6,9 +6,10 @@ import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// generated via script[generate:prisma]
import type { Repository } from "@prisma/client";
// app
+import type { RepositoryLog } from "../../types";
+import { Const } from "../../const";
import { Env } from "../../env";
// service
-import type { RepositoryLog } from "../../types";
import type { RepositoryServiceDeps } from "./types";
const GIT_LOG_NEWLINEW_FINDER_REGEXP =
@@ -19,7 +20,12 @@ const makeGetRepositoryCommitLog: ServiceMethodFactory<
[Repository, string | undefined, string | undefined, boolean | undefined],
Promise<RepositoryLog[]>
> = ({ request }) => {
- return async (repo, path = "", ref = "HEAD", onlyLast = false) => {
+ return async (
+ repo,
+ path = "",
+ ref = Const.DEFAULT_HEAD_REF,
+ onlyLast = false
+ ) => {
const parentOrg = await request.prisma.organization.findUnique({
where: {
id: repo.organizationId,
@@ -6,9 +6,10 @@ import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// generated via script[generate:prisma]
import type { Repository } from "@prisma/client";
// app
+import type { RepositoryFileContent } from "../../types";
+import { Const } from "../../const";
import { Env } from "../../env";
// service
-import type { RepositoryFileContent } from "../../types";
import type { RepositoryServiceDeps } from "./types";
const makeGetRepositoryFileContent: ServiceMethodFactory<
@@ -16,7 +17,7 @@ const makeGetRepositoryFileContent: ServiceMethodFactory<
[Repository, string, string | undefined],
Promise<null | RepositoryFileContent>
> = ({ request }) => {
- return async (repo, path, ref = "HEAD") => {
+ return async (repo, path, ref = Const.DEFAULT_HEAD_REF) => {
if (path.endsWith("/")) {
throw new Error("Could not retrieve file content for a folder.");
}
@@ -6,9 +6,10 @@ import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// generated via script[generate:prisma]
import type { Repository } from "@prisma/client";
// app
+import type { RepositoryFileContent } from "../../types";
+import { Const } from "../../const";
import { Env } from "../../env";
// service
-import type { RepositoryFileContent } from "../../types";
import type { RepositoryServiceDeps } from "./types";
const makeGetRepositoryFileContentBase64: ServiceMethodFactory<
@@ -16,7 +17,7 @@ const makeGetRepositoryFileContentBase64: ServiceMethodFactory<
[Repository, string, string | undefined],
Promise<null | RepositoryFileContent>
> = ({ request }) => {
- return async (repo, path, ref = "HEAD") => {
+ return async (repo, path, ref = Const.DEFAULT_HEAD_REF) => {
if (path.endsWith("/")) {
throw new Error("Could not retrieve file content for a folder.");
}
@@ -6,9 +6,10 @@ import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// generated via script[generate:prisma]
import type { Repository } from "@prisma/client";
// app
+import type { RepositoryFile } from "../../types";
+import { Const } from "../../const";
import { Env } from "../../env";
// service
-import type { RepositoryFile } from "../../types";
import type { RepositoryServiceDeps } from "./types";
const GIT_LS_TREE_REGEXP =
@@ -19,7 +20,7 @@ const makeGetRepositoryFiles: ServiceMethodFactory<
[Repository, string | undefined, string | undefined],
Promise<RepositoryFile[]>
> = ({ request }) => {
- return async (repo, path = "", ref = "HEAD") => {
+ return async (repo, path = "", ref = Const.DEFAULT_HEAD_REF) => {
const parentOrg = await request.prisma.organization.findUnique({
where: {
id: repo.organizationId,
@@ -6,9 +6,10 @@ import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// generated via script[generate:prisma]
import type { Repository } from "@prisma/client";
// app
+import type { RepositoryHead } from "../../types";
+import { Const } from "../../const";
import { Env } from "../../env";
// service
-import type { RepositoryHead } from "../../types";
import type { RepositoryServiceDeps } from "./types";
const GIT_TREE_ID_REGEXP = /tree[\s]+(.*)\n/im;
@@ -25,7 +26,7 @@ const makeGetRepositoryHead: ServiceMethodFactory<
[Repository, string | undefined],
Promise<RepositoryHead>
> = ({ request }) => {
- return async (repo, ref = "HEAD") => {
+ return async (repo, ref = Const.DEFAULT_HEAD_REF) => {
const parentOrg = await request.prisma.organization.findUnique({
where: {
id: repo.organizationId,
@@ -6,6 +6,7 @@ import type { ServiceMethodFactory } from "@ethicdevs/react-monolith";
// generated via script[generate:prisma]
import type { Repository } from "@prisma/client";
// app
+import { Const } from "../../const";
import { Env } from "../../env";
// service
import type { RepositoryServiceDeps } from "./types";
@@ -15,7 +16,7 @@ const makeIsFileInRepositoryPath: ServiceMethodFactory<
[Repository, string, string[], string | undefined],
Promise<string[]>
> = ({ request }) => {
- return async (repo, path, filesToMatch, ref = "HEAD") => {
+ return async (repo, path, filesToMatch, ref = Const.DEFAULT_HEAD_REF) => {
if (path !== "" && path.endsWith("/") === false) {
throw new Error("Could not search for files in a non-tree blob.");
}
@@ -11,6 +11,7 @@ import { Card, Layout, PageWrapper } from "../../components";
import RepositoryCommitSummaryLine from "../../islands/RepositoryCommitSummaryLine";
export interface RepositoryCommitsLogViewProps extends CommonProps {
+ currentRef: string;
history: RepositoryLog[];
parentOrg: Organization;
repo: Repository;
@@ -18,6 +19,7 @@ export interface RepositoryCommitsLogViewProps extends CommonProps {
const RepositoryCommitsLogView: ReactView<RepositoryCommitsLogViewProps> = ({
commonProps,
+ currentRef,
history,
parentOrg,
repo,
@@ -33,7 +35,7 @@ const RepositoryCommitsLogView: ReactView<RepositoryCommitsLogViewProps> = ({
<a href={`/${parentOrg.slug}/${repo.slug}`}>
{repo.displayName || repo.slug}
</a>
- {" / Commits"}
+ {`/ ${currentRef} / Commits`}
</h1>
<Card
style={{ width: "100%", marginTop: 32 }}
@@ -47,9 +49,10 @@ const RepositoryCommitsLogView: ReactView<RepositoryCommitsLogViewProps> = ({
themeScheme={commonProps.themeScheme}
>
<RepositoryCommitSummaryLine
+ commit={commit}
+ currentRef={currentRef}
orgSlug={parentOrg.slug}
repoSlug={repo.slug}
- commit={commit}
/>
</Card>
))}