Skip to content

Commit 15fe005

Browse files
committed
feat(clipboard): allow user to change domain used when copying to clipboard
1 parent 795f1b6 commit 15fe005

18 files changed

+142
-37
lines changed

.github/workflows/docker-images.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99

1010
jobs:
1111
build:
12-
name: Build container
12+
name: Build image
1313
runs-on: ubuntu-latest
1414
steps:
1515
- name: Checkout
@@ -35,13 +35,13 @@ jobs:
3535
run: cd server && go test -v ./...
3636

3737
- name: Login to DockerHub
38-
uses: docker/login-action@v1
38+
uses: docker/login-action@v2
3939
with:
4040
username: ${{ github.repository_owner }}
4141
password: ${{ secrets.HUB_TOKEN }}
4242

4343
- name: Log in to ghcr.io
44-
uses: docker/login-action@v1
44+
uses: docker/login-action@v2
4545
with:
4646
registry: ghcr.io
4747
username: ${{ github.repository_owner }}
@@ -82,7 +82,7 @@ jobs:
8282
npm ci install
8383
CI=false GENERATE_SOURCEMAP=false npm run build:docker
8484
85-
- name: Build and push
85+
- name: Build docker image and push
8686
id: docker_build
8787
uses: docker/build-push-action@v2
8888
with:

README.md

+9-8
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,13 @@ docker build . -t shortpaste
5252

5353
You can customize the behavior using environment variables:.
5454

55-
| Environment Variable | Default Value | Behaviour |
56-
| -------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------ |
57-
| `API_KEY` | `CHANGE-IT-ASAP` | API key used to communicate with the API. |
58-
| `BASE_PATH` | `/` | App base path (use it if the app does not have run its dedicated domain name). |
59-
| `DEBUG` | | Whether the app runs in debug mode or not (basically just more logs). |
60-
| `PORT` | 8080 | Port on which app is running, **should not be changed**. |
55+
| Environment Variable | Default Value | Behaviour |
56+
| -------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- |
57+
| `API_KEY` | `CHANGE-IT-ASAP` | API key used to communicate with the API. |
58+
| `BASE_PATH` | `/` | App base path (use it if the app does not have run its dedicated domain name). |
59+
| `DOMAIN` | | Override shortened URL domain in front, when copy to clipboard (default is the actual page domain). Example: `https://sho.rt` |
60+
| `DEBUG` | | Whether the app runs in debug mode or not (basically just more logs). |
61+
| `PORT` | 8080 | Port on which app is running, **should not be changed**. |
6162

6263
## Securing
6364

@@ -137,8 +138,8 @@ Your web browser should open on `http://localhost:3000`. The app is configured t
137138

138139
## TODO
139140

140-
- [ ] optimize build
141-
- [ ] allow user to set the public url for shortened content
141+
- [x] optimize build time
142+
- [x] allow user to set the public url for shortened content
142143
- [x] move from sqlite3 to modernc.org/sqlite to compile without CGO (and use scratch, lighter image)
143144
- [ ] display status with version
144145
- [ ] allow user to change language

front/src/App.tsx

+38-17
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,48 @@
11
import { Route } from "react-router-dom";
2-
import classes from './app.module.scss';
3-
import {MemoryRouter as Router} from "react-router-dom";
2+
import classes from "./app.module.scss";
3+
import { MemoryRouter as Router } from "react-router-dom";
44
import { ThemeProvider, createTheme } from "@mui/material";
5-
import { Content, MainMenu } from './components';
6-
import { Files, Links, Texts } from './pages';
5+
import { Content, MainMenu } from "./components";
6+
import { Files, Links, Texts } from "./pages";
7+
import AppContext from "./app_context";
8+
import { useEffect, useState } from "react";
9+
import { App as ShortApp } from "./common/data.types";
10+
import { appRepository } from "./repositories";
11+
import { config } from "./core";
712

813
const theme = createTheme({
9-
spacing: 16,
14+
spacing: 16,
1015
});
1116

1217
function App() {
13-
return <Router basename={process.env.PUBLIC_URL}>
14-
<ThemeProvider theme={theme}>
15-
<div className={classes.root}>
16-
<MainMenu />
17-
<Content>
18-
<Route path="/" element={<Links />} />
19-
<Route path="/texts" element={<Texts />} />
20-
<Route path="/files" element={<Files />} />
21-
</Content>
22-
</div>
23-
</ThemeProvider>
24-
</Router>;
18+
const [isLoading, setIsLoading] = useState(true);
19+
const [appContextValue, setAppContextValue] = useState<ShortApp>();
20+
useEffect(() => {
21+
(async() => {
22+
const app = await appRepository.get()
23+
setAppContextValue(app);
24+
config.domain = app.domain;
25+
setIsLoading(false);
26+
})();
27+
}, []);
28+
29+
return (
30+
<Router basename={process.env.PUBLIC_URL}>
31+
<ThemeProvider theme={theme}>
32+
<AppContext.Provider value={appContextValue}>
33+
<div className={classes.root}>
34+
{!isLoading ? <><MainMenu />
35+
<Content>
36+
<Route path="/" element={<Links />} />
37+
<Route path="/texts" element={<Texts />} />
38+
<Route path="/files" element={<Files />} />
39+
</Content>
40+
</> : null}
41+
</div>
42+
</AppContext.Provider>
43+
</ThemeProvider>
44+
</Router>
45+
);
2546
}
2647

2748
export default App;

front/src/app_context.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { createContext } from "react";
2+
import { App as ShortApp } from "./common/data.types";
3+
4+
const LinksContext = createContext<ShortApp|undefined>(undefined);
5+
6+
export default LinksContext;

front/src/common/api.types.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
export type Status = {
2-
status: "up";
1+
export type Config = {
2+
domain: string;
33
version: string;
44
};
55

6+
export type Status = {
7+
status: "up" | "down";
8+
};
9+
610
export type Link = {
711
id: string;
812
link: string;

front/src/common/data.types.ts

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import {
22
Link as ShortPasteLink,
33
File as ShortPasteFile,
44
Text as ShortPasteText,
5+
Config as ShortPasteConfig,
6+
Status as ShortPasteStatus,
57
} from "./api.types";
68

79
type ShortenedData = {
@@ -13,3 +15,5 @@ export type Link = ShortPasteLink & ShortenedData & {};
1315
export type File = ShortPasteFile & ShortenedData & {};
1416

1517
export type Text = ShortPasteText & ShortenedData & {};
18+
19+
export type App = ShortPasteConfig & ShortPasteStatus;

front/src/core/api.ts

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
Text as ShortPasteText,
55
File as ShortPasteFile,
66
Status,
7+
Config,
78
} from "../common/api.types";
89
import config from "./config";
910

@@ -79,6 +80,10 @@ class Api {
7980
public getStatus(): Promise<AxiosResponse<Status>> {
8081
return this._axiosInstance.get<Status>("/status");
8182
}
83+
84+
public getConfig(): Promise<AxiosResponse<Config>> {
85+
return this._axiosInstance.get<Config>("/config");
86+
}
8287
}
8388

8489
export default new Api();

front/src/core/config.ts

+9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export default class Config {
2+
static domain: string = "";
3+
24
static get apiKey(): string {
35
return process.env.REACT_APP_API_KEY || "%shortpaste-api-key-placeholder%";
46
}
@@ -19,4 +21,11 @@ export default class Config {
1921
}
2022
return `${window.location.origin}${baseURL}`;
2123
}
24+
25+
static get shortenURL(): string {
26+
if (this.domain !== "") {
27+
return this.domain;
28+
}
29+
return this.baseURL;
30+
}
2231
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { api, config } from "../core";
2+
import { App as ShortApp } from "../common/data.types";
3+
4+
export default class AppRepository {
5+
static async get(): Promise<ShortApp> {
6+
const { data: apiStatus } = await api.getStatus();
7+
const { data: apiConfig } = await api.getConfig();
8+
9+
return { ...apiStatus, ...apiConfig };
10+
}
11+
}

front/src/repositories/files_repository.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ export default class FilesRepository {
2424
}
2525

2626
static getShortURL(f: ShortPasteFile): string {
27-
return `${config.baseURL}/f/${f.id}`;
27+
return `${config.shortenURL}/f/${f.id}`;
2828
}
2929
}

front/src/repositories/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { default as appRepository } from "./app_repository";
12
export { default as linksRepository } from "./links_repository";
23
export { default as textsRepository } from "./texts_repository";
34
export { default as filesRepository } from "./files_repository";

front/src/repositories/links_repository.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ export default class LinksRepository {
2424
}
2525

2626
static getShortURL(l: ShortPasteLink): string {
27-
return `${config.baseURL}/l/${l.id}`;
27+
return `${config.shortenURL}/l/${l.id}`;
2828
}
2929
}

front/src/repositories/texts_repository.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ export default class TextsRepository {
2424
}
2525

2626
static getShortURL(t: ShortPasteText): string {
27-
return `${config.baseURL}/t/${t.id}`;
27+
return `${config.shortenURL}/t/${t.id}`;
2828
}
2929
}

server/api/api.go

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ func Router(r chi.Router) {
99
r.Use(middleware.SetHeader("Content-Type", "application/json"))
1010
r.Use(CheckApiKey)
1111

12+
r.Get(`/config`, ConfigList)
13+
r.Get(`/status`, StatusList)
14+
1215
r.Get(`/links`, LinksList)
1316
r.Post(`/links`, LinkAdd)
1417
r.Delete(`/links/{id}`, LinkDelete)

server/api/config.go

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package api
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
"shortpaste/core/config"
7+
)
8+
9+
func ConfigList(w http.ResponseWriter, r *http.Request) {
10+
var list = map[string]interface{}{
11+
"domain": config.GetDomain(),
12+
"version": config.AppVersion(),
13+
}
14+
body, _ := json.Marshal(list)
15+
w.Write(body)
16+
}

server/api/status.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@ package api
33
import (
44
"encoding/json"
55
"net/http"
6-
"shortpaste/core/config"
76
)
87

98
func StatusList(w http.ResponseWriter, r *http.Request) {
109
var list = map[string]interface{}{
11-
"status": "up",
12-
"version": config.AppVersion(),
10+
"status": "up",
1311
}
1412
body, _ := json.Marshal(list)
1513
w.Write(body)

server/core/config/domain.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package config
2+
3+
import "os"
4+
5+
func GetDomain() string {
6+
domain := os.Getenv("DOMAIN")
7+
return domain
8+
}

server/core/config/domain_test.go

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package config
2+
3+
import (
4+
"os"
5+
"testing"
6+
)
7+
8+
func TestGetDomain(t *testing.T) {
9+
os.Setenv("DOMAIN", "")
10+
11+
domain := GetDomain()
12+
13+
expectedDomain := ""
14+
15+
if expectedDomain != domain {
16+
t.Fatalf("Expected base path %s, but got %s", expectedDomain, domain)
17+
}
18+
}

0 commit comments

Comments
 (0)