mirror of
https://github.com/photoprism/photoprism.git
synced 2025-10-07 09:41:16 +08:00
API: Move swagger.json to /internal/api and embed it in build #2132
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
23
Makefile
23
Makefile
@@ -95,16 +95,27 @@ logs:
|
|||||||
help:
|
help:
|
||||||
@echo "For build instructions, visit <https://docs.photoprism.app/developer-guide/>."
|
@echo "For build instructions, visit <https://docs.photoprism.app/developer-guide/>."
|
||||||
docs: swag
|
docs: swag
|
||||||
swag:
|
swag: swag-json
|
||||||
@echo "Generating Swagger API documentation..."
|
swag-json:
|
||||||
swag init --generatedTime --parseDependency --parseDepth 1 --dir internal/api -g api.go -o ./assets/docs/api/v1
|
@echo "Generating ./internal/api/swagger.json..."
|
||||||
|
swag init --ot json --parseDependency --parseDepth 1 --dir internal/api -g api.go -o ./internal/api
|
||||||
|
swag-yaml:
|
||||||
|
@echo "Generating ./internal/api/swagger.yaml..."
|
||||||
|
swag init --ot yaml --parseDependency --parseDepth 1 --dir internal/api -g api.go -o ./internal/api
|
||||||
|
swag-clean:
|
||||||
|
@echo "Removing Swagger API documentation..."
|
||||||
|
rm -rf ./assets/docs/api
|
||||||
|
rm -f ./internal/api/swagger.json
|
||||||
|
rm -f ./internal/api/swagger.yaml
|
||||||
swag-fmt:
|
swag-fmt:
|
||||||
@echo "Formatting Swagger API documentation..."
|
@echo "Formatting Swagger API annotations..."
|
||||||
swag fmt --dir internal/api
|
swag fmt --dir internal/api
|
||||||
swag-go:
|
swag-go:
|
||||||
docker run --rm --pull always -v ./assets/docs:/assets/docs swaggerapi/swagger-codegen-cli generate -i /assets/docs/api/v1/swagger.json -l go -o /assets/docs/api/v1/go
|
swag init --ot json --generatedTime --parseDependency --parseDepth 1 --dir internal/api -g api.go -o ./assets/docs/api/v1
|
||||||
|
docker run --rm -u $(UID) --pull always -v ./assets/docs:/assets/docs swaggerapi/swagger-codegen-cli generate -i /assets/docs/api/v1/swagger.json -l go -o /assets/docs/api/v1/go
|
||||||
swag-html:
|
swag-html:
|
||||||
docker run --rm --pull always -v ./assets/docs:/assets/docs swaggerapi/swagger-codegen-cli generate -i /assets/docs/api/v1/swagger.json -l html2 -o /assets/docs/api/v1/html
|
swag init --ot json --generatedTime --parseDependency --parseDepth 1 --dir internal/api -g api.go -o ./assets/docs/api/v1
|
||||||
|
docker run --rm -u $(UID) --pull always -v ./assets/docs:/assets/docs swaggerapi/swagger-codegen-cli generate -i /assets/docs/api/v1/swagger.json -l html2 -o /assets/docs/api/v1/html
|
||||||
notice:
|
notice:
|
||||||
@echo "Creating license report for Go dependencies..."
|
@echo "Creating license report for Go dependencies..."
|
||||||
go-licenses report ./internal/... ./pkg/... --template=.report.tmpl > NOTICE
|
go-licenses report ./internal/... ./pkg/... --template=.report.tmpl > NOTICE
|
||||||
|
@@ -16,7 +16,16 @@ import (
|
|||||||
|
|
||||||
// SearchAlbums finds albums and returns them as JSON.
|
// SearchAlbums finds albums and returns them as JSON.
|
||||||
//
|
//
|
||||||
// GET /api/v1/albums
|
// @Summary finds albums and returns them as JSON
|
||||||
|
// @Id SearchAlbums
|
||||||
|
// @Tags Albums
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} search.AlbumResults
|
||||||
|
// @Failure 400,404 {object} i18n.Response
|
||||||
|
// @Param count query int true "maximum number of results" minimum(1) maximum(100000)
|
||||||
|
// @Param offset query int false "search result offset" minimum(0) maximum(100000)
|
||||||
|
// @Param order query string false "sort order" Enums(favorites, name, title, added, edited)
|
||||||
|
// @Router /api/v1/albums [get]
|
||||||
func SearchAlbums(router *gin.RouterGroup) {
|
func SearchAlbums(router *gin.RouterGroup) {
|
||||||
router.GET("/albums", func(c *gin.Context) {
|
router.GET("/albums", func(c *gin.Context) {
|
||||||
s := AuthAny(c, acl.ResourceAlbums, acl.Permissions{acl.ActionSearch, acl.ActionView, acl.AccessShared})
|
s := AuthAny(c, acl.ResourceAlbums, acl.Permissions{acl.ActionSearch, acl.ActionView, acl.AccessShared})
|
||||||
|
@@ -47,4 +47,5 @@ import (
|
|||||||
// @externalDocs.description Learn more ›
|
// @externalDocs.description Learn more ›
|
||||||
// @externalDocs.url https://docs.photoprism.app/developer-guide/api/
|
// @externalDocs.url https://docs.photoprism.app/developer-guide/api/
|
||||||
// @version v1
|
// @version v1
|
||||||
|
// @host demo.photoprism.app
|
||||||
// @query.collection.format multi
|
// @query.collection.format multi
|
||||||
|
@@ -4,27 +4,34 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"bytes"
|
||||||
|
_ "embed"
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/photoprism/get"
|
|
||||||
files "github.com/swaggo/files"
|
files "github.com/swaggo/files"
|
||||||
swagger "github.com/swaggo/gin-swagger"
|
swagger "github.com/swaggo/gin-swagger"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/photoprism/get"
|
||||||
|
"github.com/photoprism/photoprism/pkg/header"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:embed swagger.json
|
||||||
|
var swaggerJSON []byte
|
||||||
|
|
||||||
// GetDocs registers the Swagger API documentation endpoints.
|
// GetDocs registers the Swagger API documentation endpoints.
|
||||||
func GetDocs(router *gin.RouterGroup) {
|
func GetDocs(router *gin.RouterGroup) {
|
||||||
|
// Get global configuration.
|
||||||
conf := get.Config()
|
conf := get.Config()
|
||||||
swaggerFile := filepath.Join(conf.AssetsPath(), "docs/api/v1/swagger.json")
|
|
||||||
|
|
||||||
if !fs.FileExistsNotEmpty(swaggerFile) {
|
// Serve swagger.json, with the default host "demo.photoprism.app" being replaced by the configured hostname.
|
||||||
return
|
router.GET("swagger.json", func(c *gin.Context) {
|
||||||
|
c.Data(http.StatusOK, header.ContentTypeJson, bytes.ReplaceAll(swaggerJSON, []byte("demo.photoprism.app"), []byte(conf.SiteHost())))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Serve Swagger UI.
|
||||||
|
if handler := swagger.WrapHandler(files.Handler, swagger.URL(conf.ApiUri()+"/swagger.json")); handler != nil {
|
||||||
|
router.GET("/docs", handler)
|
||||||
|
router.GET("/docs/*any", handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
router.StaticFile("/swagger.json", swaggerFile)
|
|
||||||
handler := swagger.WrapHandler(files.Handler, swagger.URL(conf.ApiUri()+"/swagger.json"))
|
|
||||||
router.GET("/docs", handler)
|
|
||||||
router.GET("/docs/*any", handler)
|
|
||||||
}
|
}
|
||||||
|
@@ -35,9 +35,9 @@ func SaveSidecarYaml(photo *entity.Photo) {
|
|||||||
_ = photo.SaveSidecarYaml(conf.OriginalsPath(), conf.SidecarPath())
|
_ = photo.SaveSidecarYaml(conf.OriginalsPath(), conf.SidecarPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPhoto returns photo details as JSON.
|
// GetPhoto returns picture details as JSON.
|
||||||
//
|
//
|
||||||
// @Summary returns photo details as JSON
|
// @Summary returns picture details as JSON
|
||||||
// @Id GetPhoto
|
// @Id GetPhoto
|
||||||
// @Tags Photos
|
// @Tags Photos
|
||||||
// @Produce json
|
// @Produce json
|
||||||
@@ -64,7 +64,7 @@ func GetPhoto(router *gin.RouterGroup) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePhoto updates photo details and returns them as JSON.
|
// UpdatePhoto updates picture details and returns them as JSON.
|
||||||
//
|
//
|
||||||
// PUT /api/v1/photos/:uid
|
// PUT /api/v1/photos/:uid
|
||||||
func UpdatePhoto(router *gin.RouterGroup) {
|
func UpdatePhoto(router *gin.RouterGroup) {
|
||||||
@@ -161,7 +161,7 @@ func GetPhotoDownload(router *gin.RouterGroup) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPhotoYaml returns photo details as YAML.
|
// GetPhotoYaml returns picture details as YAML.
|
||||||
//
|
//
|
||||||
// The request parameters are:
|
// The request parameters are:
|
||||||
//
|
//
|
||||||
|
@@ -15,10 +15,19 @@ import (
|
|||||||
"github.com/photoprism/photoprism/pkg/i18n"
|
"github.com/photoprism/photoprism/pkg/i18n"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SearchPhotos searches the pictures index and returns the result as JSON.
|
// SearchPhotos finds pictures and returns them as JSON.
|
||||||
// See form.SearchPhotos for supported search params and data types.
|
|
||||||
//
|
//
|
||||||
// GET /api/v1/photos
|
// @Summary finds pictures and returns them as JSON
|
||||||
|
// @Id SearchPhotos
|
||||||
|
// @Tags Photos
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} search.PhotoResults
|
||||||
|
// @Failure 400,404 {object} i18n.Response
|
||||||
|
// @Param count query int true "maximum number of files" minimum(1) maximum(100000)
|
||||||
|
// @Param offset query int false "file offset" minimum(0) maximum(100000)
|
||||||
|
// @Param order query string false "sort order" Enums(favorites, name, title, added, edited)
|
||||||
|
// @Param merged query bool false "groups consecutive files that belong to the same photo"
|
||||||
|
// @Router /api/v1/photos [get]
|
||||||
func SearchPhotos(router *gin.RouterGroup) {
|
func SearchPhotos(router *gin.RouterGroup) {
|
||||||
// searchPhotos checking authorization and parses the search request.
|
// searchPhotos checking authorization and parses the search request.
|
||||||
searchForm := func(c *gin.Context) (f form.SearchPhotos, s *entity.Session, err error) {
|
searchForm := func(c *gin.Context) (f form.SearchPhotos, s *entity.Session, err error) {
|
||||||
|
@@ -9,6 +9,71 @@
|
|||||||
"host": "demo.photoprism.app",
|
"host": "demo.photoprism.app",
|
||||||
"paths": {
|
"paths": {
|
||||||
"/api/v1/albums": {
|
"/api/v1/albums": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Albums"
|
||||||
|
],
|
||||||
|
"summary": "finds albums and returns them as JSON",
|
||||||
|
"operationId": "SearchAlbums",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"maximum": 100000,
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "maximum number of results",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"maximum": 100000,
|
||||||
|
"minimum": 0,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "search result offset",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enum": [
|
||||||
|
"favorites",
|
||||||
|
"name",
|
||||||
|
"title",
|
||||||
|
"added",
|
||||||
|
"edited"
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
"description": "sort order",
|
||||||
|
"name": "order",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/search.Album"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/i18n.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/i18n.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"tags": [
|
"tags": [
|
||||||
"Albums"
|
"Albums"
|
||||||
@@ -220,6 +285,79 @@
|
|||||||
"responses": {}
|
"responses": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/api/v1/photos": {
|
||||||
|
"get": {
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Photos"
|
||||||
|
],
|
||||||
|
"summary": "finds pictures and returns them as JSON",
|
||||||
|
"operationId": "SearchPhotos",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"maximum": 100000,
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "maximum number of files",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"maximum": 100000,
|
||||||
|
"minimum": 0,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "file offset",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enum": [
|
||||||
|
"favorites",
|
||||||
|
"name",
|
||||||
|
"title",
|
||||||
|
"added",
|
||||||
|
"edited"
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
"description": "sort order",
|
||||||
|
"name": "order",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "groups consecutive files that belong to the same photo",
|
||||||
|
"name": "merged",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/search.Photo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/i18n.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/i18n.Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/photos/{uid}": {
|
"/api/v1/photos/{uid}": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
@@ -228,7 +366,7 @@
|
|||||||
"tags": [
|
"tags": [
|
||||||
"Photos"
|
"Photos"
|
||||||
],
|
],
|
||||||
"summary": "returns photo details as JSON",
|
"summary": "returns picture details as JSON",
|
||||||
"operationId": "GetPhoto",
|
"operationId": "GetPhoto",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -1203,9 +1341,315 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"search.Album": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"Caption": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Category": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Country": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CreatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Day": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"DeletedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Favorite": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"Filter": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"LinkCount": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Location": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Month": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Notes": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Order": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ParentUID": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"PhotoCount": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Private": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"Slug": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"State": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Template": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Thumb": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ThumbSrc": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"UID": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"UpdatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Year": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"search.Photo": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"Altitude": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"CameraID": {
|
||||||
|
"description": "Camera",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"CameraMake": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CameraModel": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CameraSerial": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CameraSrc": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CellAccuracy": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"CellID": {
|
||||||
|
"description": "Cell",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CheckedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Color": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Country": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"CreatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Day": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"DeletedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Description": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"DocumentID": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Duration": {
|
||||||
|
"$ref": "#/definitions/time.Duration"
|
||||||
|
},
|
||||||
|
"EditedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Exposure": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"FNumber": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"Faces": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Favorite": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"FileName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"FileRoot": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"FileUID": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Files": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/entity.File"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FocalLength": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Hash": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Height": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"ID": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"InstanceID": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Iso": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Lat": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"LensID": {
|
||||||
|
"description": "Lens",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"LensMake": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"LensModel": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Lng": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"Merged": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"Month": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"OriginalName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Panorama": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"Path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"PlaceCity": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"PlaceCountry": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"PlaceID": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"PlaceLabel": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"PlaceSrc": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"PlaceState": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Portrait": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"Private": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"Quality": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Resolution": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Scan": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"Stack": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"TakenAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"TakenAtLocal": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"TakenSrc": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"TimeZone": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"TypeSrc": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"UID": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"UpdatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Width": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"Year": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"time.Duration": {
|
"time.Duration": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
-9223372036854775808,
|
||||||
|
9223372036854775807,
|
||||||
|
1,
|
||||||
|
1000,
|
||||||
|
1000000,
|
||||||
|
1000000000,
|
||||||
|
60000000000,
|
||||||
|
3600000000000,
|
||||||
-9223372036854775808,
|
-9223372036854775808,
|
||||||
9223372036854775807,
|
9223372036854775807,
|
||||||
1,
|
1,
|
||||||
@@ -1218,8 +1662,6 @@
|
|||||||
1000,
|
1000,
|
||||||
1000000,
|
1000000,
|
||||||
1000000000,
|
1000000000,
|
||||||
60000000000,
|
|
||||||
3600000000000,
|
|
||||||
1,
|
1,
|
||||||
1000,
|
1000,
|
||||||
1000000,
|
1000000,
|
||||||
@@ -1242,6 +1684,8 @@
|
|||||||
"Second",
|
"Second",
|
||||||
"Minute",
|
"Minute",
|
||||||
"Hour",
|
"Hour",
|
||||||
|
"minDuration",
|
||||||
|
"maxDuration",
|
||||||
"Nanosecond",
|
"Nanosecond",
|
||||||
"Microsecond",
|
"Microsecond",
|
||||||
"Millisecond",
|
"Millisecond",
|
||||||
@@ -1252,6 +1696,10 @@
|
|||||||
"Microsecond",
|
"Microsecond",
|
||||||
"Millisecond",
|
"Millisecond",
|
||||||
"Second",
|
"Second",
|
||||||
|
"Nanosecond",
|
||||||
|
"Microsecond",
|
||||||
|
"Millisecond",
|
||||||
|
"Second",
|
||||||
"Minute",
|
"Minute",
|
||||||
"Hour",
|
"Hour",
|
||||||
"Nanosecond",
|
"Nanosecond",
|
@@ -2,12 +2,12 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/photoprism/photoprism/internal/config"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -3,11 +3,11 @@ package api
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/config"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/pkg/capture"
|
"github.com/photoprism/photoprism/pkg/capture"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPasswdCommand(t *testing.T) {
|
func TestPasswdCommand(t *testing.T) {
|
||||||
|
@@ -127,7 +127,7 @@ func (c *Config) DatabaseServer() string {
|
|||||||
if c.DatabaseDriver() == SQLite3 {
|
if c.DatabaseDriver() == SQLite3 {
|
||||||
return ""
|
return ""
|
||||||
} else if c.options.DatabaseServer == "" {
|
} else if c.options.DatabaseServer == "" {
|
||||||
return "localhost"
|
return localhost
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.options.DatabaseServer
|
return c.options.DatabaseServer
|
||||||
|
@@ -6,6 +6,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const localhost = "localhost"
|
||||||
|
|
||||||
// BaseUri returns the site base URI for a given resource.
|
// BaseUri returns the site base URI for a given resource.
|
||||||
func (c *Config) BaseUri(res string) string {
|
func (c *Config) BaseUri(res string) string {
|
||||||
if c.SiteUrl() == "" {
|
if c.SiteUrl() == "" {
|
||||||
@@ -68,15 +70,28 @@ func (c *Config) SiteHttps() bool {
|
|||||||
return strings.HasPrefix(c.options.SiteUrl, "https://")
|
return strings.HasPrefix(c.options.SiteUrl, "https://")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SiteDomain returns the public server domain.
|
// SiteDomain returns the public hostname without protocol or post.
|
||||||
func (c *Config) SiteDomain() string {
|
func (c *Config) SiteDomain() string {
|
||||||
if u, err := url.Parse(c.SiteUrl()); err != nil {
|
if u, err := url.Parse(c.SiteUrl()); err != nil {
|
||||||
return "localhost"
|
return localhost
|
||||||
} else {
|
} else {
|
||||||
return u.Hostname()
|
return u.Hostname()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SiteHost returns the public hostname and port number in the format "domain:port".
|
||||||
|
func (c *Config) SiteHost() string {
|
||||||
|
if u, err := url.Parse(c.SiteUrl()); err != nil {
|
||||||
|
return localhost
|
||||||
|
} else if hostname := u.Hostname(); hostname == "" {
|
||||||
|
return localhost
|
||||||
|
} else if port := u.Port(); port != "" {
|
||||||
|
return fmt.Sprintf("%s:%s", hostname, port)
|
||||||
|
} else {
|
||||||
|
return hostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SiteAuthor returns the site author / copyright.
|
// SiteAuthor returns the site author / copyright.
|
||||||
func (c *Config) SiteAuthor() string {
|
func (c *Config) SiteAuthor() string {
|
||||||
return c.options.SiteAuthor
|
return c.options.SiteAuthor
|
||||||
|
@@ -82,11 +82,21 @@ func TestConfig_SiteHttps(t *testing.T) {
|
|||||||
func TestConfig_SiteDomain(t *testing.T) {
|
func TestConfig_SiteDomain(t *testing.T) {
|
||||||
c := NewConfig(CliTestContext())
|
c := NewConfig(CliTestContext())
|
||||||
|
|
||||||
assert.Equal(t, "localhost", c.SiteDomain())
|
assert.Equal(t, localhost, c.SiteDomain())
|
||||||
c.options.SiteUrl = "https://foo.bar.com:2342/"
|
c.options.SiteUrl = "https://foo.bar.com:2342/"
|
||||||
assert.Equal(t, "foo.bar.com", c.SiteDomain())
|
assert.Equal(t, "foo.bar.com", c.SiteDomain())
|
||||||
c.options.SiteUrl = ""
|
c.options.SiteUrl = ""
|
||||||
assert.Equal(t, "localhost", c.SiteDomain())
|
assert.Equal(t, localhost, c.SiteDomain())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfig_SiteHost(t *testing.T) {
|
||||||
|
c := NewConfig(CliTestContext())
|
||||||
|
|
||||||
|
assert.Equal(t, "localhost:2342", c.SiteHost())
|
||||||
|
c.options.SiteUrl = "https://foo.bar.com:2342/"
|
||||||
|
assert.Equal(t, "foo.bar.com:2342", c.SiteHost())
|
||||||
|
c.options.SiteUrl = ""
|
||||||
|
assert.Equal(t, "localhost:2342", c.SiteHost())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfig_SitePreview(t *testing.T) {
|
func TestConfig_SitePreview(t *testing.T) {
|
||||||
|
Reference in New Issue
Block a user