From eac9577af884224103617ddd45ce1ddc3aa7039a Mon Sep 17 00:00:00 2001
From: Hannaeko <19394895+hannaeko@users.noreply.github.com>
Date: Mon, 10 Aug 2026 13:59:24 +0200
Subject: [PATCH 1/8] add support for scribouilli backend and refactor
configuration
---
assets/scripts/GitAgent.ts | 19 ++-
assets/scripts/actions/current-repository.ts | 23 +--
assets/scripts/actions/setup.ts | 26 ++--
assets/scripts/components/Header.svelte | 12 +-
assets/scripts/components/Skeleton.svelte | 2 +-
.../scripts/components/screens/Account.svelte | 51 ++-----
.../components/screens/ChooseAccount.svelte | 19 +--
.../components/screens/CreateAccount.svelte | 98 ++----------
.../components/screens/CreateNewSite.svelte | 7 +-
.../scripts/components/screens/Login.svelte | 18 ++-
.../components/screens/intern/Editeur.svelte | 12 +-
assets/scripts/config.ts | 93 +++++++++++-
assets/scripts/oauth-services-api/github.ts | 7 +
assets/scripts/oauth-services-api/gitlab.ts | 7 +
assets/scripts/oauth-services-api/index.ts | 38 ++++-
.../scripts/oauth-services-api/scribouilli.ts | 142 ++++++++++++++++++
assets/scripts/routes/account.ts | 15 +-
assets/scripts/routes/after-oauth-login.ts | 25 +--
assets/scripts/routes/create-account.ts | 13 +-
assets/scripts/routes/login.ts | 80 +++++-----
assets/scripts/scribouilliGitRepo.ts | 29 +---
assets/scripts/store.ts | 3 +-
assets/scripts/types/atelier.ts | 18 +++
assets/scripts/types/git.ts | 5 +
assets/styles/styles.css | 23 ++-
25 files changed, 503 insertions(+), 282 deletions(-)
create mode 100644 assets/scripts/oauth-services-api/scribouilli.ts
diff --git a/assets/scripts/GitAgent.ts b/assets/scripts/GitAgent.ts
index 0d4e8f16..652a8204 100644
--- a/assets/scripts/GitAgent.ts
+++ b/assets/scripts/GitAgent.ts
@@ -13,16 +13,15 @@ import FS from '@isomorphic-git/lightning-fs'
import git from 'isomorphic-git'
import http from 'isomorphic-git/http/web'
-const DEFAULT_CORS_PROXY_URL = 'https://cors.isomorphic-git.org'
-
-import type { CommitObject, GitAuth } from 'isomorphic-git'
+import type { CommitObject } from 'isomorphic-git'
import type { ResolutionOption } from './store.ts'
+import { OAuthServiceAPI } from './types/git.ts'
export default class GitAgent {
#fs
#remoteURL
#repoId
- #corsProxyURL
+ #corsProxyURL: string | undefined = undefined
#onAuth
#onMergeConflict
@@ -34,14 +33,14 @@ export default class GitAgent {
constructor({
repoId,
remoteURL,
- corsProxyURL = DEFAULT_CORS_PROXY_URL,
- auth,
+ corsProxyURL,
+ gitServiceProvider,
onMergeConflict,
}: {
repoId: string
remoteURL: string
- corsProxyURL?: string
- auth: GitAuth
+ corsProxyURL?: string,
+ gitServiceProvider: OAuthServiceAPI,
onMergeConflict?:
| ((resolutionOptions: ResolutionOption[]) => void)
| undefined
@@ -50,6 +49,8 @@ export default class GitAgent {
this.#repoId = repoId
this.#remoteURL = remoteURL
+ const auth = gitServiceProvider.getOauthUsernameAndPassword()
+
this.#onAuth = () => auth
this.#onMergeConflict = onMergeConflict
this.#corsProxyURL = corsProxyURL
@@ -83,6 +84,7 @@ export default class GitAgent {
singleBranch: true,
corsProxy: this.#corsProxyURL,
depth: 5,
+ onAuth: this.#onAuth,
})
}
@@ -191,6 +193,7 @@ export default class GitAgent {
singleBranch: false, // we want all the branches
dir: this.#repoDirectory,
corsProxy: this.#corsProxyURL,
+ onAuth: this.#onAuth,
})
}
diff --git a/assets/scripts/actions/current-repository.ts b/assets/scripts/actions/current-repository.ts
index 1075b45e..52324ec4 100644
--- a/assets/scripts/actions/current-repository.ts
+++ b/assets/scripts/actions/current-repository.ts
@@ -2,10 +2,7 @@ import page from 'page'
import yaml from 'js-yaml'
import store, { type PartialStore } from './../store.ts'
-import ScribouilliGitRepo, {
- makeRepoId,
- makePublicRepositoryURL,
-} from './../scribouilliGitRepo.ts'
+import ScribouilliGitRepo from './../scribouilliGitRepo.ts'
import GitAgent from '../GitAgent.ts'
import { handleErrors, logMessage } from './../utils.ts'
import { fetchAuthenticatedUserLogin } from './current-user.ts'
@@ -17,7 +14,7 @@ import { file } from './file.ts'
import { getPagesList } from './page.ts'
import { getArticlesList } from './article.ts'
import { getOAuthServiceAPI } from '../oauth-services-api/index.ts'
-import { CUSTOM_CSS_PATH } from '../config.ts'
+import { CUSTOM_CSS_PATH, PROVIDERS_MAP } from '../config.ts'
import type { BuildStatus } from '../types/git.ts'
export const getCurrentRepoPages = () => {
@@ -65,26 +62,30 @@ export const setCurrentRepositoryFromQuerystring = async (
}
const origin = oAuthProvider.origin
- const repoId = makeRepoId(owner, repoName)
+ const provider = PROVIDERS_MAP.get(oAuthProvider.id)
+ if (!provider) {
+ throw new TypeError(`Unkown provider ${oAuthProvider.id}`)
+ }
+ const oAuthServiceAPI = getOAuthServiceAPI()
const scribouilliGitRepo = new ScribouilliGitRepo({
owner,
repoName,
- repoId,
+ repoType: provider.type,
origin: origin,
- publicRepositoryURL: makePublicRepositoryURL(owner, repoName, origin),
gitServiceProvider: getOAuthServiceAPI(),
})
store.mutations.setCurrentRepository(scribouilliGitRepo)
const gitAgent = new GitAgent({
- repoId,
- remoteURL: `${origin}/${repoId}.git`,
+ repoId: oAuthServiceAPI.makeRepoId(owner, repoName),
+ remoteURL: oAuthServiceAPI.makePublicRepositoryURL(owner, repoName),
+ corsProxyURL: provider.corsProxy,
+ gitServiceProvider: oAuthServiceAPI,
onMergeConflict: resolutionOptions => {
store.mutations.setConflict(resolutionOptions)
},
- auth: getOAuthServiceAPI().getOauthUsernameAndPassword(),
})
store.mutations.setGitAgent(gitAgent)
diff --git a/assets/scripts/actions/setup.ts b/assets/scripts/actions/setup.ts
index 73726ec2..3876020c 100644
--- a/assets/scripts/actions/setup.ts
+++ b/assets/scripts/actions/setup.ts
@@ -1,10 +1,7 @@
import page from 'page'
import store, { ResolutionOption } from './../store.ts'
-import ScribouilliGitRepo, {
- makePublicRepositoryURL,
- makeRepoId,
-} from './../scribouilliGitRepo.ts'
+import ScribouilliGitRepo from './../scribouilliGitRepo.ts'
import { getOAuthServiceAPI } from './../oauth-services-api/index.ts'
import { makeAtelierListPageURL } from './../routes/urls.ts'
import { logMessage } from './../utils.ts'
@@ -12,6 +9,7 @@ import { setBaseUrlInConfigIfNecessary } from './current-repository.ts'
import GitAgent from '../GitAgent.ts'
import git from 'isomorphic-git'
import type { GitSiteTemplate } from '../types/git.ts'
+import { PROVIDERS_MAP } from '../config.ts'
const waitRepoReady = (
scribouilliGitRepo: ScribouilliGitRepo,
@@ -130,34 +128,36 @@ export const createRepositoryForCurrentAccount = async (
}
const origin = oAuthProvider.origin
+ const provider = PROVIDERS_MAP.get(oAuthProvider.id)
+ if (!provider) {
+ throw new TypeError(`Unkown provider ${oAuthProvider.id}`)
+ }
+ const oAuthServiceAPI = getOAuthServiceAPI()
const scribouilliGitRepo = new ScribouilliGitRepo({
owner: owner,
repoName: escapedRepoName,
+ repoType: provider.type,
origin: origin,
- publicRepositoryURL: makePublicRepositoryURL(
- owner,
- escapedRepoName,
- origin,
- ),
- gitServiceProvider: getOAuthServiceAPI(),
+ gitServiceProvider: oAuthServiceAPI,
})
store.mutations.setCurrentRepository(scribouilliGitRepo)
return (
- getOAuthServiceAPI()
+ oAuthServiceAPI
.createDefaultRepository(scribouilliGitRepo, template)
.then(({ remoteURL }) => {
const gitAgent = new GitAgent({
- repoId: makeRepoId(owner, escapedRepoName),
+ repoId: oAuthServiceAPI.makeRepoId(owner, escapedRepoName),
remoteURL: remoteURL,
+ corsProxyURL: provider.corsProxy,
onMergeConflict: (
resolutionOptions: ResolutionOption[] | undefined,
) => {
store.mutations.setConflict(resolutionOptions)
},
- auth: getOAuthServiceAPI().getOauthUsernameAndPassword(),
+ gitServiceProvider: oAuthServiceAPI,
})
store.mutations.setGitAgent(gitAgent)
diff --git a/assets/scripts/components/Header.svelte b/assets/scripts/components/Header.svelte
index 2eae015a..8153c2de 100644
--- a/assets/scripts/components/Header.svelte
+++ b/assets/scripts/components/Header.svelte
@@ -1,6 +1,7 @@
Avez-vous un compte GitHub ?
-
-
- Avez-vous un compte sur gitlab.com ?
-
-
- Avez-vous un compte sur git.scribouilli.org ?
+ {#if provider.type === 'github' }
+ Avez-vous un compte GitHub ?
+ {:else}
+ Avez-vous un compte sur { provider.id } ?
+ {/if}
+ Pour vérifier que vous n'êtes pas un robot, envoyez-nous un mail à + coucou@scribouilli.org en indiquant : +
+ +Pour information, la création du compte pourrait prendre quelques jours de notre côté, on vous préviendra par mail quand c'est fait ! +
+ `, + corsProxy: DEFAULT_CORS_PROXY_URL, + }, + { + id: 'github.com', + origin: 'https://github.com', + clientId: '64ecce0b01397c2499a6', + type: 'github', + description: `Microsoft GitHub®, si vous l'utilisez déjà.`, + name: 'GitHub', + signupEnabled: true, + signupLink: 'https://github.com/signup', + signupInstructions:` ++ Pour pouvoir publier votre contenu, il faut que Scribouilli se connecte + à un compte GitHub. +
+La création va se passer sur GitHub.com.
+Elle comporte 3 étapes :
+
Pour pouvoir publier votre contenu, il faut que Scribouilli se connecte
à un compte GitHub.
@@ -109,8 +111,10 @@ export const PROVIDERS: ScribouilliBackendProvider[] = [
`,
corsProxy: DEFAULT_CORS_PROXY_URL,
- }
+ },
]
-export const PROVIDERS_MAP = new Map(PROVIDERS.map(provider => [provider.id, provider]))
+export const PROVIDERS_MAP = new Map(
+ PROVIDERS.map(provider => [provider.id, provider]),
+)
export const svelteTarget: Element = document.body
diff --git a/assets/scripts/oauth-services-api/github.ts b/assets/scripts/oauth-services-api/github.ts
index de2b0cef..9456cba5 100644
--- a/assets/scripts/oauth-services-api/github.ts
+++ b/assets/scripts/oauth-services-api/github.ts
@@ -199,7 +199,7 @@ export default class GitHubAPI implements OAuthServiceAPI {
makeRepoId = defaultMakeRepoId
- makePublicRepositoryURL(owner: string, repoName: string ): string {
- return defaultMakePublicRepositoryURL(owner, repoName, 'https://github.com')
+ makePublicRepositoryURL(owner: string, repoName: string): string {
+ return defaultMakePublicRepositoryURL(owner, repoName, 'https://github.com')
}
}
diff --git a/assets/scripts/oauth-services-api/gitlab.ts b/assets/scripts/oauth-services-api/gitlab.ts
index 94aba3f3..a04a24c0 100644
--- a/assets/scripts/oauth-services-api/gitlab.ts
+++ b/assets/scripts/oauth-services-api/gitlab.ts
@@ -240,7 +240,7 @@ export default class GitLabAPI implements OAuthServiceAPI {
makeRepoId = defaultMakeRepoId
- makePublicRepositoryURL(owner: string, repoName: string ): string {
- return defaultMakePublicRepositoryURL(owner, repoName, this.origin)
+ makePublicRepositoryURL(owner: string, repoName: string): string {
+ return defaultMakePublicRepositoryURL(owner, repoName, this.origin)
}
}
diff --git a/assets/scripts/oauth-services-api/index.ts b/assets/scripts/oauth-services-api/index.ts
index d5919e05..a109ac61 100644
--- a/assets/scripts/oauth-services-api/index.ts
+++ b/assets/scripts/oauth-services-api/index.ts
@@ -55,7 +55,6 @@ export const getOAuthServiceAPI = (): OAuthServiceAPI => {
return oAuthServiceAPI
}
-
/**
* @param owner may be an individual Github user or an organisation
*/
diff --git a/assets/scripts/oauth-services-api/scribouilli.ts b/assets/scripts/oauth-services-api/scribouilli.ts
index acc1779d..77ba7cd9 100644
--- a/assets/scripts/oauth-services-api/scribouilli.ts
+++ b/assets/scripts/oauth-services-api/scribouilli.ts
@@ -1,142 +1,167 @@
import ScribouilliGitRepo from '../scribouilliGitRepo.ts'
-import type { BuildStatus, GithubRepository, GitSiteTemplate, OAuthServiceAPI } from '../types/git.ts'
+import type {
+ BuildStatus,
+ GithubRepository,
+ GitSiteTemplate,
+ OAuthServiceAPI,
+} from '../types/git.ts'
export default class ScribouilliBackend implements OAuthServiceAPI {
-
- private accessToken: string | undefined
- private origin
- private authenticatedUser:
- | undefined
- | { id: string, login: string, email: string }
-
- constructor(accessToken: string, origin: string) {7
- this.accessToken = accessToken
- this.origin = origin
- this.authenticatedUser = undefined
+ private accessToken: string | undefined
+ private origin
+ private authenticatedUser:
+ | undefined
+ | { id: string; login: string; email: string }
+
+ constructor(accessToken: string, origin: string) {
+ 7
+ this.accessToken = accessToken
+ this.origin = origin
+ this.authenticatedUser = undefined
+ }
+
+ get apiBaseUrl() {
+ return `${this.origin}/api`
+ }
+
+ async callAPI(url: string, requestParams: RequestInit = {}) {
+ requestParams.headers ??= {}
+ requestParams.headers['Authorization'] = 'Bearer ' + this.accessToken
+
+ const httpResp = await fetch(`${this.apiBaseUrl}${url}`, requestParams)
+ if (httpResp.status === 404) {
+ throw 'NOT_FOUND'
}
-
- get apiBaseUrl() {
- return `${this.origin}/api`
+ if (httpResp.status === 401) {
+ this.accessToken = undefined
+ console.debug('this accessToken : ', this.accessToken)
+ throw 'INVALIDATE_TOKEN'
}
+ return httpResp
+ }
- async callAPI(url: string, requestParams: RequestInit = {}) {
- requestParams.headers ??= {}
- requestParams.headers['Authorization'] = 'Bearer ' + this.accessToken
-
- const httpResp = await fetch(`${this.apiBaseUrl}${url}`, requestParams)
- if (httpResp.status === 404) {
- throw 'NOT_FOUND'
- }
- if (httpResp.status === 401) {
- this.accessToken = undefined
- console.debug('this accessToken : ', this.accessToken)
- throw 'INVALIDATE_TOKEN'
- }
- return httpResp
+ getOauthUsernameAndPassword() {
+ if (!this.accessToken) {
+ throw new TypeError('Missing accessToken')
}
- getOauthUsernameAndPassword() {
- if (!this.accessToken) {
- throw new TypeError('Missing accessToken')
- }
-
- return { username: 'token', password: this.accessToken }
- }
-
-
- async getAuthenticatedUser() {
- if (this.authenticatedUser) {
- return this.authenticatedUser
- }
+ return { username: 'token', password: this.accessToken }
+ }
- const response = await this.callAPI(`/profile`)
- const user = await response.json()
- this.authenticatedUser = {
- login: user.email,
- email: user.email,
- id: user.id,
- }
- return this.authenticatedUser
+ async getAuthenticatedUser() {
+ if (this.authenticatedUser) {
+ return this.authenticatedUser
}
- async getUserEmails() {
- const { email } = await this.getAuthenticatedUser();
- return [{
- email,
- primary: true
- }]
+ const response = await this.callAPI(`/profile`)
+ const user = await response.json()
+ this.authenticatedUser = {
+ login: user.email,
+ email: user.email,
+ id: user.id,
}
-
- async createDefaultRepository(scribouilliGitRepo: ScribouilliGitRepo, template: GitSiteTemplate): Promise<{ remoteURL: string; }> {
- const { repoName } = scribouilliGitRepo;
- await this.callAPI(`/websites`, {
- method: 'POST',
- headers: {
- 'content-type': 'application/json'
- },
- body: JSON.stringify({
- name: repoName,
- template_url: template.url,
- })
- })
-
- return {remoteURL: this.makePublicRepositoryURL('', repoName)}
- }
-
- async isRepositoryReady(scribouilliGitRepo: ScribouilliGitRepo): Promise