finish up translations and setup doc server stuff
This commit is contained in:
@ -6,7 +6,7 @@ api.elf: $(GOSRCS)
|
||||
go build -o $@
|
||||
|
||||
run:
|
||||
API_DEBUG=true API_FRONTEND_URL=http://localhost:5173/ API_PASSWORD=test ./api.elf
|
||||
API_DEBUG=true API_APP_URL=http://localhost:5173/ API_PASSWORD=test ./api.elf
|
||||
|
||||
format:
|
||||
gofmt -s -w .
|
||||
|
@ -38,10 +38,10 @@ func (c *Type) Load() (err error) {
|
||||
// default options
|
||||
c.Options = []Option{
|
||||
{Name: "debug", Value: "false", Type: OPTION_TYPE_BOOL, Required: true}, // should display debug messgaes?
|
||||
{Name: "index", Value: "true", Type: OPTION_TYPE_BOOL, Required: false}, // should display the index page (view/index.md)?
|
||||
|
||||
{Name: "api_url", Value: "http://localhost:7001/", Type: OPTION_TYPE_URL, Required: true}, // API URL for the website
|
||||
{Name: "frontend_url", Value: "http://localhost:5173/", Type: OPTION_TYPE_URL, Required: true}, // frontend application URL for the website
|
||||
{Name: "url", Value: "http://localhost:7001/", Type: OPTION_TYPE_URL, Required: true}, // API URL for the website
|
||||
{Name: "app_url", Value: "http://localhost:7002/", Type: OPTION_TYPE_URL, Required: true}, // frontend application URL for the website
|
||||
{Name: "doc_url", Value: "http://localhost:7003/", Type: OPTION_TYPE_URL, Required: true}, // documentation URL for the website
|
||||
|
||||
{Name: "password", Value: "", Type: OPTION_TYPE_STR, Required: true}, // admin password
|
||||
{Name: "host", Value: "0.0.0.0:7001", Type: OPTION_TYPE_STR, Required: true}, // host the server should listen on
|
||||
|
@ -5,7 +5,6 @@ go 1.21.3
|
||||
require (
|
||||
github.com/gofiber/fiber/v2 v2.52.5
|
||||
github.com/mattn/go-sqlite3 v1.14.24
|
||||
github.com/russross/blackfriday/v2 v2.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -17,8 +17,6 @@ github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBW
|
||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||
|
@ -3,30 +3,11 @@ package routes
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/ngn13/website/api/config"
|
||||
"github.com/ngn13/website/api/util"
|
||||
)
|
||||
|
||||
func GET_Index(c *fiber.Ctx) error {
|
||||
var (
|
||||
md []byte
|
||||
err error
|
||||
)
|
||||
|
||||
conf := c.Locals("config").(*config.Type)
|
||||
doc := conf.GetURL("doc_url")
|
||||
|
||||
if !conf.GetBool("index") {
|
||||
return util.ErrNotFound(c)
|
||||
}
|
||||
|
||||
frontend := conf.GetURL("frontend_url")
|
||||
api := conf.GetURL("api_url")
|
||||
|
||||
if md, err = util.Render("views/index.md", fiber.Map{
|
||||
"frontend": frontend,
|
||||
"api": api,
|
||||
}); err != nil {
|
||||
return util.ErrInternal(c, err)
|
||||
}
|
||||
|
||||
return util.Markdown(c, md)
|
||||
return c.Redirect(doc.JoinPath("/api").String())
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func GET_News(c *fiber.Ctx) error {
|
||||
|
||||
db := c.Locals("database").(*database.Type)
|
||||
conf := c.Locals("config").(*config.Type)
|
||||
frontend := conf.GetURL("frontend_url")
|
||||
app := conf.GetURL("app_url")
|
||||
lang := c.Params("lang")
|
||||
|
||||
if lang == "" || len(lang) != 2 {
|
||||
@ -63,14 +63,16 @@ func GET_News(c *fiber.Ctx) error {
|
||||
})
|
||||
|
||||
if feed, err = util.Render("views/news.xml", fiber.Map{
|
||||
"frontend": frontend,
|
||||
"updated": time.Now().Format(time.RFC3339),
|
||||
"entries": entries,
|
||||
"lang": lang,
|
||||
"updated": time.Now().Format(time.RFC3339),
|
||||
"entries": entries,
|
||||
"lang": lang,
|
||||
"app": app,
|
||||
}); err != nil {
|
||||
return util.ErrInternal(c, err)
|
||||
}
|
||||
|
||||
c.Set("Content-Disposition", "attachment; filename=\"news.atom\"")
|
||||
c.Set("Content-Type", "application/atom+xml; charset=utf-8")
|
||||
|
||||
return c.Send(feed)
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/ngn13/website/api/config"
|
||||
"github.com/russross/blackfriday/v2"
|
||||
)
|
||||
|
||||
func IP(c *fiber.Ctx) string {
|
||||
@ -20,15 +19,6 @@ func IP(c *fiber.Ctx) string {
|
||||
return c.IP()
|
||||
}
|
||||
|
||||
func Markdown(c *fiber.Ctx, raw []byte) error {
|
||||
exts := blackfriday.FencedCode
|
||||
exts |= blackfriday.NoEmptyLineBeforeBlock
|
||||
exts |= blackfriday.HardLineBreak
|
||||
|
||||
c.Set("Content-Type", "text/html; charset=utf-8")
|
||||
return c.Send(blackfriday.Run(raw, blackfriday.WithExtensions(exts)))
|
||||
}
|
||||
|
||||
func JSON(c *fiber.Ctx, code int, data fiber.Map) error {
|
||||
if data == nil {
|
||||
data = fiber.Map{}
|
||||
|
@ -1,178 +0,0 @@
|
||||
<!-- This is the markdown file that will be served by the index route -->
|
||||
|
||||
<style>
|
||||
* {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
|
||||
# [{{.api.Host}}]({{.api.String}})
|
||||
This is the API for my personal website, [{{.frontend.Host}}]({{.frontend.String}}).
|
||||
|
||||
It stores information about the self-hosted services I provide and it also allows me
|
||||
to publish news and updates about these services using an Atom feed. It's written in
|
||||
Go and uses SQLite for storage. Licensed under GNU GPL version 3.
|
||||
|
||||
**Source code and the license is available at**: [https://github.com/ngn13/website](https://github.com/ngn13/website)
|
||||
**You can report issues to**: [https://github.com/ngn13/website/issues](https://github.com/ngn13/website/issues)
|
||||
|
||||
The rest of this document contains documentation for all the available API endpoints.
|
||||
|
||||
## Version 1 Endpoints
|
||||
Each version 1 endpoint, can be accessed using the /v1 route.
|
||||
|
||||
All the endpoints return JSON formatted data.
|
||||
|
||||
### Errors
|
||||
If any error occurs, you will get a non-200 response. And the JSON data will have an
|
||||
"error" key, which will contain information about the error that occured, in the
|
||||
string format. This is the only JSON key that will be set in non-200 responses.
|
||||
|
||||
### Results
|
||||
If no error occurs, "error" key will be set to an emtpy string (""). If the endpoint
|
||||
returns any data, this will be stored using the "result" key. The "result" have a
|
||||
different expected type and a format for each endpoint.
|
||||
|
||||
### Multilang
|
||||
Some "result" formats may use a structure called "Multilang". This is a simple JSON
|
||||
structure that includes one key for each supported language. The key is named after
|
||||
the language it represents. Currently only supported languages are:
|
||||
- English (`en`)
|
||||
- Turkish (`tr`)
|
||||
|
||||
So each multilang structure, will have **at least** one of these keys.
|
||||
|
||||
Here is an example multilang structure:
|
||||
```
|
||||
{
|
||||
"en": "Hello, world!",
|
||||
"tr": "Merhaba, dünya!"
|
||||
}
|
||||
```
|
||||
If a "result" field is using a multilang structure, it will be specified as "Multilang"
|
||||
in the rest of the documentation.
|
||||
|
||||
### Administrator routes
|
||||
The endpoints under the "/v1/admin" route, are administrator-only routes. To access
|
||||
these routes you'll need to specfiy and password using the "Authorization" header.
|
||||
If the password you specify, matches with the password specified using the
|
||||
`API_PASSWORD` environment variable, you will be able to access the route.
|
||||
|
||||
### GET /v1/services
|
||||
Returns a list of available services. Each service has the following JSON format:
|
||||
```
|
||||
{
|
||||
"name": "Test Service",
|
||||
"desc": {
|
||||
"en": "Service used for testing the API",
|
||||
"tr": "API'ı test etmek için kullanılan servis"
|
||||
},
|
||||
"check_time": 1735861944,
|
||||
"check_res": 1,
|
||||
"check_url": "http://localhost:7001",
|
||||
"clear": "http://localhost:7001",
|
||||
"onion": "",
|
||||
"i2p": ""
|
||||
}
|
||||
```
|
||||
Where:
|
||||
- `name`: Service name (string)
|
||||
- `desc`: Service description (Multilang)
|
||||
- `check_time`: Last time status check time for the service, set 0 if status checking is
|
||||
not supported for this service/status checking is disabled (integer, UNIX timestamp)
|
||||
- `check_res`: Last service status check result (integer)
|
||||
* 0 if the service is down
|
||||
* 1 if the service is up
|
||||
* 2 if the service is up, but slow
|
||||
* 3 if the service doesn't support status checking/status checking is disabled
|
||||
- `check_url`: URL used for service's status check (string, empty if none)
|
||||
- `clear`: Clearnet URL for the service (string, empty string if none)
|
||||
- `onion`: Onion (TOR) URL for the service (string, empty string if none)
|
||||
- `i2p`: I2P URL for the service (string, empty string if none)
|
||||
|
||||
You can also get information about a specific service by specifying it's name using
|
||||
a URL query named "name".
|
||||
|
||||
### GET /v1/news/:language
|
||||
Returns a Atom feed of news for the given language. Supports languages that are supported
|
||||
by Multilang.
|
||||
|
||||
### GET /v1/metrics
|
||||
Returns metrics about the API usage. The metric data has the following format:
|
||||
```
|
||||
{
|
||||
"number":8,
|
||||
"since":1736294400,
|
||||
"total":8
|
||||
}
|
||||
```
|
||||
Where:
|
||||
- `number`: Visitor number of the the current visitor (integer)
|
||||
- `since`: Metric collection start date (integer, UNIX timestamp)
|
||||
- `total`: Total number of visitors (integer)
|
||||
|
||||
Note that visitor number may change after a certain amount of requests by other clients,
|
||||
if the client wants to preserve it's visitor number, it should save it somewhere.
|
||||
|
||||
### GET /v1/admin/logs
|
||||
Returns a list of administrator logs. Each log has the following JSON format:
|
||||
```
|
||||
{
|
||||
"action": "Added service \"Test Service\"",
|
||||
"time": 1735861794
|
||||
}
|
||||
```
|
||||
Where:
|
||||
- `action`: Action that the administrator performed (string)
|
||||
- `time`: Time when the administrator action was performed (integer, UNIX timestamp)
|
||||
|
||||
Client can get the logs for only a single address, by setting the URL query "addr".
|
||||
|
||||
### PUT /v1/admin/service/add
|
||||
Creates a new service. The request body needs to contain JSON data, and it needs to
|
||||
have the JSON format used to represent a service. See "/v1/services/all" route to
|
||||
see this format.
|
||||
|
||||
Returns no data on success.
|
||||
|
||||
### DELETE /v1/admin/service/del
|
||||
Deletes a service. The client needs to specify the name of the service to delete, by
|
||||
setting the URL query "name".
|
||||
|
||||
Returns no data on success.
|
||||
|
||||
### GET /v1/admin/service/check
|
||||
Forces a status check for all the services.
|
||||
|
||||
Returns no data on success.
|
||||
|
||||
### PUT /v1/admin/news/add
|
||||
Creates a news post. The request body needs to contain JSON data, and it needs
|
||||
to use the following JSON format:
|
||||
```
|
||||
{
|
||||
"id": "test_news",
|
||||
"title": {
|
||||
"en": "Very important news",
|
||||
"tr": "Çok önemli haber"
|
||||
},
|
||||
"author": "ngn",
|
||||
"content": {
|
||||
"en": "Just letting you know that I'm testing the API",
|
||||
"tr": "Sadece API'ı test ettiğimi bilmenizi istedim"
|
||||
}
|
||||
}
|
||||
```
|
||||
Where:
|
||||
- `id`: Unique ID for the news post (string)
|
||||
- `title`: Title for the news post (Multilang)
|
||||
- `author`: Author of the news post (string)
|
||||
- `content`: Contents of the news post (Multilang)
|
||||
|
||||
Returns no data on success.
|
||||
|
||||
### DELETE /v1/admin/news/del
|
||||
Deletes a news post. The client needs to specify the ID of the news post to delete,
|
||||
by setting the URL query "id".
|
||||
|
||||
Returns no data on success.
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>{{.frontend.Host}} news</title>
|
||||
<title>{{.app.Host}} news</title>
|
||||
<updated>{{.updated}}</updated>
|
||||
<subtitle>News and updates about my projects and self-hosted services</subtitle>
|
||||
<link href="{{.frontend.JoinPath "/news"}}"></link>
|
||||
<link href="{{.app.JoinPath "/news"}}"></link>
|
||||
{{ range .entries }}
|
||||
<entry>
|
||||
<title>{{.Title}}</title>
|
||||
|
Reference in New Issue
Block a user