From 1df989c1c5b232005497d9930a1fb8c8e44d1440 Mon Sep 17 00:00:00 2001 From: Wim Brand Date: Wed, 29 Jul 2020 16:29:25 +0200 Subject: [PATCH] support markdown pages --- res/include/md/about.md | 79 +++ res/include/md/apidoc.md | 644 +++++++++++++++++++ res/include/md/donation.md | 25 + res/include/style/layout.css | 29 +- res/template/about.html | 128 ---- res/template/apidoc.html | 92 --- res/template/donation.html | 41 -- res/template/fragments/api/file.html | 311 --------- res/template/fragments/api/filesystem.html | 162 ----- res/template/fragments/api/list.html | 180 ------ res/template/fragments/markdown_wrapper.html | 18 + webcontroller/web_controller.go | 68 +- 12 files changed, 858 insertions(+), 919 deletions(-) create mode 100644 res/include/md/about.md create mode 100644 res/include/md/apidoc.md create mode 100644 res/include/md/donation.md delete mode 100644 res/template/about.html delete mode 100644 res/template/apidoc.html delete mode 100644 res/template/donation.html delete mode 100644 res/template/fragments/api/file.html delete mode 100644 res/template/fragments/api/filesystem.html delete mode 100644 res/template/fragments/api/list.html create mode 100644 res/template/fragments/markdown_wrapper.html diff --git a/res/include/md/about.md b/res/include/md/about.md new file mode 100644 index 0000000..99c9a76 --- /dev/null +++ b/res/include/md/about.md @@ -0,0 +1,79 @@ +# Questions and Answers + +## For how long will my files be stored? + +Files will be removed if they have not been viewed for 30 days. A view is +counted when someone visits the file's download page (pixeldrain.com/u/somefile) +or views the file through a list the file is included in +(pixeldrain.com/l/somelist). + +If you upload a file while logged into your pixeldrain account you will be able +to delete the file yourself from the download page of the file. If you are not +logged in and you accidentally upload something you shouldn't have, just don't +share the link. The file will expire eventually. File links are not indexed or +published anywhere. As long as you don't share it nobody will see it. + +## Does pixeldrain cost any money? + +No, pixeldrain is completely free at the moment. While there is an advertisement +on the file downloading page, it doesn't generate nearly enough revenue to pay +for maintaining this service. That's why I'd really appreciate it if you could +spare some coins. Possible methods for donating are: + + * + {{template `patreon.svg` .}} Support me on Patreon and get some perks too! + + * Bitcoin: + [1Ne7hGuvnfz9EFTRD3PLWVeaJTX9oA1QUr](bitcoin:1Ne7hGuvnfz9EFTRD3PLWVeaJTX9oA1QUr?label=Pixeldrain%20Donation) + * BasicAttentionToken: Donate BAT by clicking the BAT icon in your address bar. + If you don't have Brave browser yet you can download it here: Install Brave. Installing and using Brave with this + referral link also counts as a 5$ donation. + * Siacoin: + 26117c19ca3975b315d663dcbbc19cf9c07274f441689d4392ed380b2337589ef1aacfbdc93f + (this address points directly at the storage backend. Donations will be used + for paying storage contracts with Sia hosts) + * PayPal: + Donate with PayPal + +## Do I need to register an account? + +Not if you don't want to. You're free to use pixeldrain completely anonymously. +Without a pixeldrain account you can upload files, download files and create +lists of files. And view your uploaded files on the [history page](/history). +This page only shows files which were uploaded anonymously in this web browser. + +By registering an account on pixeldrain you will be able to access your files +from any device with a web browser. Files you upload and lists you create will +be linked to your pixeldrain account and will show up on your [personal home +page](/user). + +## What cookies does pixeldrain use? + +When logging in to a pixeldrain account a cookie named 'pd_auth_key' will be +installed. This cookie keeps your login session active. When you delete it you +will be logged out of your account. + +When you use the style selector on the [Appearance](/appearance) page a cookie +called 'style' will be set. This cookie controls the appearance of the website +for you. + +When uploading a file pixeldrain will save a list of file links on your +browser's local storage. This data is **only** used for viewing your upload +history on the [history page](/history). + +## Legality + +I cannot be held liable for any illegal and / or copyrighted material that's +uploaded by the users of this application. Files uploaded to this website are +subjected to local laws. If laws are being broken, and I've been notified of the +fact I'll have to delete the offending content. If you find any files on this +domain that break the law, please contact me at +[abuse@pixeldrain.com](mailto:abuse@pixeldrain.com), and I'll take care of it. + +Please share responsibly. + +For other questions you can reach me at +[support@pixeldrain.com](mailto:support@pixeldrain.com) diff --git a/res/include/md/apidoc.md b/res/include/md/apidoc.md new file mode 100644 index 0000000..fdc78d7 --- /dev/null +++ b/res/include/md/apidoc.md @@ -0,0 +1,644 @@ +# Pixeldrain API documentation + +The methods for uploading and retrieving files don't require an API key. The +methods for creating and retrieving lists also don't require an API key. All +methods which delete or modify a resource **do** require an API key. + +API keys can be obtained from the login API. + +Some JSON responses include fields which end in "_href" (some people don't know +this, but "href" stands for "Hypertext Reference", the more you know). These +point to different places in the API, which you can retrieve with a GET request. +The path is to be appended to the API URL, so "/file/someid/thumbnail" becomes +"{{apiUrl}}/file/someid/thumbnail". + +The base URL for the API is "{{apiUrl}}", all paths below are relative to that +URL. + +## Form value order + +I recommend you put files at the end of every file upload form. By doing this +the pixeldrain server can respond to malformed requests before the file upload +finishes and this may save you a lot of time and bandwidth when uploading large +files. Make sure your HTTP client has support for premature responses, +pixeldrain uses them a lot. If the server responds before your request is +finished it will always indicate an error and you may abort the connection. + +## File Methods + +
+POST/file +
+ +### Description + +Upload a file. + +### Parameters + +Param | Type | Required | Maximum Size | Default | Description +----------|----------------|----------|----------------|---------------------|----------------------------------- +name | string | false | 255 characters | multipart file name | Name of the file to upload +anonymous | boolean | false | N/A | false | File is not linked to user if true +file | multipart file | true | 1000^3 bytes | none | File to upload + +### Returns + +HTTP 200: OK +``` +{ + "success": true, + "id": "abc123" // ID of the newly uploaded file +} +``` + +HTTP 422: Unprocessable Entity +``` +{ + "success": false, + "value": "no_file", + "message": "The file does not exist or is empty." +} +``` + +HTTP 500: Internal Server Error +``` +{ + "success": false, + "value": "internal", + "message": "An internal server error occurred." +} +``` + +HTTP 413: Payload Too Large +``` +{ + "success": false, + "value": "file_too_large", + "message": "The file you tried to upload is too large" +} +``` + +HTTP 500: Internal Server Error +``` +{ + "success": false, + "value": "writing", + "message": "Something went wrong while writing the file to disk, the server may be out of storage space." +} +``` + +HTTP 413: Payload Too Large +``` +{ + "success": false, + "value": "name_too_long", + "message": "File Name is too long, Max 255 characters allowed." +} +``` +
+
+ +
+GET/file/{id} +
+ +### Description + +Returns the full file associated with the ID. Supports byte range requests. + +When '?download' is added to the URL the server will send an attachment header +instead of inline rendering, which causes the browser to show a 'Save File' +dialog. + +Warning: If a file is using too much bandwidth it can be rate limited. The rate +limit will be enabled if a file has ten times more downloads than views. The +owner of a file can always download it. When a file is rate limited the user +will need to fill out a captcha in order to continue downloading the file. The +captcha will only appear on the file viewer page (pixeldrain.com/u/{id}). Rate +limiting has been added to prevent the spread of viruses and to stop direct +linking. + +Pixeldrain also includes a virus scanner. If a virus has been detected in a file +the user will also have to fill in a captcha to download it. + +### Parameters + +Param | Required | Location | Description +---------|----------|----------|------------------------------------------ +id | true | URL | ID of the file to request +download | false | URL | Sends attachment header instead of inline + +### Returns + +``` +HTTP 200: OK + +Requested file data +``` + +HTTP 404: Not Found +``` +{ + "success": false, + "value": "not_found", + "message": "The entity you requested could not be found" +} +``` + +HTTP 403: Forbidden +``` +{ + "success": false, + "value": "file_rate_limited_captcha_required", + "message": "This file is using too much bandwidth. For anonymous downloads a captcha is required now. The captcha entry is available on the download page" +} +``` + +HTTP 403: Forbidden +``` +{ + "success": false, + "value": "virus_detected_captcha_required", + "message": "This file has been marked as malware by our scanning systems. To avoid infecting other systems through automated downloads we require you to enter a captcha. The captcha entry is available on the download page" +} +``` +
+
+ +
+GET/file/{id}/info +
+ +### Description + +Returns information about one or more files. You can also put a comma separated +list of file IDs in the URL and it will return an array of file info, instead of +a single object. + +### Parameters + +Param | Required | Location | Description +------|----------|----------|--------------- +id | true | URL | ID of the file + +### Returns + +HTTP 200: OK +``` +{ + "success": true, + "id": "1234abcd", + "name": "screenshot.png", + "date_upload": 2020-02-04T18:34:05.706801Z, + "date_last_view": 2020-02-04T18:34:05.706801Z, + "size": 5694837, // Bytes + "views" 1234, // Amount of unique file views + "bandwidth_used": 1234567890, // Bytes + "mime_type" "image/png", + "thumbnail_href": "/file/1234abcd/thumbnail" // Link to a thumbnail of this file +} +``` + +HTTP 404: Not Found +``` +{ + "success": false, + "value": "file_not_found" +} +``` +
+
+ + + +## List Methods + +
+POST/list +
+ +### Description + +Creates a list of files that can be viewed together on the file viewer page. + +### Parameters + +POST body should be a JSON object, example below. A list can contain at most +10000 files. If you try to add more the request will fail. + +#### Example +``` +{ + "title": "My beautiful photos", // Defaults to "Pixeldrain List" + "anonymous": false / true, // If true this list will not be linked to your user account. Defaults to "false" + "files": [ // Ordered array of files to add to the list + { + "id": "abc123", + "description": "First photo of the week, such a beautiful valley" + }, + { + "id": "123abc", + "description": "The week went by so quickly, here's a photo from the plane back" + } + ] +} +``` + +### Returns + +HTTP 200: OK +``` +{ + "success": true, + "id": "yay137" // ID of the newly created list +} +``` + +HTTP 422: Unprocessable Entity +``` +{ + "success": false, + "value": "list_file_not_found", + "message": "File Oh42No was not found in the database.", + "extra": { + "file_not_found": "0h42No" // The file you tried to add with this ID does not exist + } +} +``` + +HTTP 413: Payload too large +``` +{ + "success": false, + "value": "too_many_files", + "message": "This list contains too many files, max 10000 allowed." +} +``` + +HTTP 422: Unprocessable Entity +``` +{ + "success": false, + "value": "json_parse_failed", + "message": "The JSON object in the request body could not be read." +} +``` + +HTTP 413: Payload too large +``` +{ + "success": false, + "value": "title_too_long", + "message": "The title of this list is too long, max 300 characters allowed." +} +``` + +HTTP 413: Payload too large +``` +{ + "success": false, + "value": "description_too_long", + "message": "The description of one of the files in the list is too long, max 3000 characters allowed." +} +``` + +HTTP 422: Unprocessable Entity +``` +{ + "success": false, + "value": "cannot_create_empty_list", + "message": "You cannot make a list with no files." +} +``` +
+
+ +
+GET/list/{id} +
+ +### Description + +Returns information about a file list and the files in it. + +### Parameters + + +Param | Required | Location | Description +------|----------|----------|--------------- +id | true | URL | ID of the list + +### Returns + +The API will return some basic information about every file. Every file also has +a "detail_href" field which contains a URL to the info API of the file. Follow +that link to get more information about the file like size, checksum, mime type, +etc. The address is relative to the API URL and should be appended to the end. + +HTTP 200: OK +``` +{ + "success": true, + "id": "L8bhwx", + "title": "Rust in Peace", + "date_created": 2020-02-04T18:34:13.466276Z, + "files": [ + // These structures are the same as the file info response, except for the detail_href and description fields + { + "detail_href": "/file/_SqVWi/info", + "description": "", + "success": true, + "id": "_SqVWi", + "name": "01 Holy Wars... The Punishment Due.mp3", + "size": 123456, + "date_created": 2020-02-04T18:34:13.466276Z, + "date_last_view": 2020-02-04T18:34:13.466276Z, + "mime_type": "audio/mp3", + "views": 1, + "bandwidth_used": 1234567890, + "thumbnail_href": "/file/_SqVWi/thumbnail" + }, + { + "detail_href": "/file/RKwgZb/info", + "description": "", + "success": true, + "id": "RKwgZb", + "name": "02 Hangar 18.mp3", + "size": 123456, + "date_created": 2020-02-04T18:34:13.466276Z, + "date_last_view": 2020-02-04T18:34:13.466276Z, + "mime_type": "audio/mp3", + "views": 2, + "bandwidth_used": 1234567890, + "thumbnail_href": "/file/RKwgZb/thumbnail" + }, + { + "detail_href": "/file/DRaL_e/info", + "description": "", + "success": true, + "id": "DRaL_e", + "name": "03 Take No Prisoners.mp3", + "size": 123456, + "date_created": 2020-02-04T18:34:13.466276Z, + "date_last_view": 2020-02-04T18:34:13.466276Z, + "mime_type": "audio/mp3", + "views": 3, + "bandwidth_used": 1234567890, + "thumbnail_href": "/file/DRaL_e/thumbnail" + } + ] +} +``` + +HTTP 404: Not Found +``` +{ + "success": false, + "value": "list_not_found", +} +``` +
+
+ + diff --git a/res/include/md/donation.md b/res/include/md/donation.md new file mode 100644 index 0000000..7776d8d --- /dev/null +++ b/res/include/md/donation.md @@ -0,0 +1,25 @@ +# Thank you for supporting pixeldrain! + +{{$success := .URLQuery.Get "success"}} +{{if eq $success "true"}} + {{if .Authenticated}} +Dear {{.User.Username}}, + +Thank you for your donation. I really appreciate it! + +Sincerely, Fornax. + {{else}} +Thank you for your donation! You are amazing. + +Sincerely, Fornax. + {{end}} +{{else}} +It seems you have canceled your donation. I don't blame you, money is expensive :) + +If this was not your intention, you're welcome to try again by clicking this button: + +Donate with PayPal + + +Sincerely, Fornax. +{{end}} diff --git a/res/include/style/layout.css b/res/include/style/layout.css index 9c0604e..711fbae 100644 --- a/res/include/style/layout.css +++ b/res/include/style/layout.css @@ -305,7 +305,7 @@ a:hover {text-decoration: underline;} } table:not(.form) {border-collapse: collapse; width: 100%;} tr:not(.form) {border-bottom: 1px var(--layer_2_color_border) solid;} -tr > td {padding: 0.3em;} +tr > td, tr > th {padding: 0.3em;} @media(max-width: 30em) { /* Forms will be stacked on small screens */ tr.form > td { @@ -319,7 +319,7 @@ tr > td {padding: 0.3em;} pre{ padding: 2px; border-bottom: 1px var(--layer_2_color_border) solid; - overflow-x: scroll; + overflow-x: auto; } .big_button{ @@ -371,6 +371,31 @@ pre{ color: var(--highlight_color); } +/* API documentation markup */ + +details { + border-top: 1px solid; + border-bottom: 1px solid; + margin: 15px 0 15px 0; +} +details > summary { + padding: 2px; + font-family: monospace; +} +details > summary > .method { + display: inline-block; + width: 80px; +} +details > div { + padding: 8px; +} + +details.request_get { border-color: #3636ff; background-color: rgba(32, 32, 255, 0.2); } +details.request_post { border-color: #00d000; background-color: rgba(0, 255, 0, 0.05); } +details.request_delete { border-color: #B00000; background-color: rgba(255, 0, 0, 0.05); } +details.request_put { border-color: #B06000; background-color: rgba(255, 128, 0, 0.05); } +details.request_patch { border-color: #6000B0; background-color: rgba(128, 0, 255, 0.1); } + /* Form fields */ .form_input {width: 100%;} diff --git a/res/template/about.html b/res/template/about.html deleted file mode 100644 index f2da95f..0000000 --- a/res/template/about.html +++ /dev/null @@ -1,128 +0,0 @@ -{{define "about"}} - - - {{template "meta_tags" "About"}} - {{template "user_style" .}} - - - - {{template "page_top" .}} -

About pixeldrain

-
-

Questions and Answers

- -

For how long will my files be stored?

-

- Files will be removed if they have not been viewed for 30 days. - A view is counted when someone visits the file's download page - (pixeldrain.com/u/somefile) or views the file through a list the - file is included in (pixeldrain.com/l/somelist). -

-

- If you upload a file while logged into your pixeldrain account - you will be able to delete the file yourself from the download - page of the file. If you are not logged in and you accidentally - upload something you shouldn't have, just don't share the link. - The file will expire eventually. File links are not indexed or - published anywhere. As long as you don't share it nobody will - see it. -

- -

Does pixeldrain cost any money?

-

- No, pixeldrain is completely free at the moment. While there is - an advertisement on the file downloading page, it doesn't - generate nearly enough revenue to pay for maintaining this - service. That's why I'd really appreciate it if you could spare - some coins. Possible methods for donating are: -

- - -

Do I need to register an account?

-

- Not if you don't want to. You're free to use pixeldrain - completely anonymously. Without a pixeldrain account you can - upload files, download files and create lists of files. And view - your uploaded files on the history page. - This page only shows files which were uploaded anonymously in - this web browser. -

-

- By registering an account on pixeldrain you will be able to - access your files from any device with a web browser. Files you - upload and lists you create will be linked to your pixeldrain - account and will show up on your personal home - page. -

- -

What cookies does pixeldrain use?

-

- When logging in to a pixeldrain account a cookie named - 'pd_auth_key' will be installed. This cookie keeps your login - session active. When you delete it you will be logged out of - your account. -

-

- When you use the style selector on the Appearance page a cookie called 'style' - will be set. This cookie controls the appearance of the website - for you. -

-

- When uploading a file pixeldrain will save a list of file links - on your browser's local storage. This data is - only used for viewing your upload history on the history page. -

- -

Legality

-

- I cannot be held liable for any illegal and / or copyrighted - material that's uploaded by the users of this application. Files - uploaded to this website are subjected to local laws. If laws - are being broken, and I've been notified of the fact I'll have - to delete the offending content. If you find any files on this - domain that break the law, please contact me at - abuse@pixeldrain.com, - and I'll take care of it. -
Please share responsibly. -

-

- For other questions you can reach me at - support@pixeldrain.com -

-
- {{template "page_bottom" .}} - {{template "analytics"}} - - -{{end}} diff --git a/res/template/apidoc.html b/res/template/apidoc.html deleted file mode 100644 index a248d61..0000000 --- a/res/template/apidoc.html +++ /dev/null @@ -1,92 +0,0 @@ -{{define "apidoc"}} - - - {{template "meta_tags" "API Documentation"}} - {{template "user_style" .}} - - - - - {{template "page_top" .}} -

Pixeldrain API documentation

- -
-

- Welcome to the pixeldrain API documentation. -
- The methods for uploading and retrieving files don't require an - API key. The methods for creating and retrieving lists also - don't require an API key. All methods which delete or modify a - resource do require an API key. -
- API keys can be obtained from the login API. -

-

- Some JSON responses include fields which end in "_href" (some - people don't know this, but "href" stands for "Hypertext - Reference", the more you know). These point to different places - in the API, which you can retrieve with a GET request. The path - is to be appended to the API URL, so "/file/someid/thumbnail" - becomes "{{apiUrl}}/file/someid/thumbnail". -

-

- The base URL for the API is "{{apiUrl}}", all paths below are - relative to that URL. -

- -

Form value order

-

- I recommend you put files at the end of every file upload form. - By doing this the pixeldrain server can respond to malformed - requests before the file upload finishes and this may save you a - lot of time and bandwidth when uploading large files. Make sure - your HTTP client has support for premature responses, pixeldrain - uses them a lot. If the server responds before your request is - finished it will always indicate an error and you may abort the - connection. -

- -

File Methods

- {{template "api-file-post"}} - {{template "api-file-id-get"}} - {{template "api-file-id-info-get"}} - {{template "api-file-id-thumbnail-get"}} - {{/*template "api-file-id-delete"*/}} - -

List Methods

- {{template "api-list-post"}} - {{template "api-list-get"}} - - - {{/*template "api-filesystem-path-post"*/}} - {{/*template "api-filesystem-path-get"*/}} - {{/*template "api-filesystem-path-delete"*/}} -
- {{template "page_bottom" .}} - {{template "analytics"}} - - -{{end}} diff --git a/res/template/donation.html b/res/template/donation.html deleted file mode 100644 index 284e607..0000000 --- a/res/template/donation.html +++ /dev/null @@ -1,41 +0,0 @@ -{{define "donation"}} - - - - {{template "meta_tags" "Thank you for supporting pixeldrain!"}} - {{template "user_style" .}} - - - {{template "page_top" .}} -
-
- {{$success := .URLQuery.Get "success"}} - {{if eq $success "true"}} - {{if .Authenticated}} - Dear {{.User.Username}}, -

- Thank you for your donation. I really appreciate it! -

- Sincerely,
- Fornax - {{else}} - Thank you for your donation! You are amazing. -

- Sincerely,
- Fornax - {{end}} - {{else}} - It seems you have canceled your donation. I don't blame you, money is expensive :) -

- If this was not your intention, you're welcome to try again by clicking this button: - Donate with PayPal -

- Sincerely,
- Fornax - {{end}} -
- {{template "page_bottom" .}} - {{template "analytics"}} - - -{{end}} diff --git a/res/template/fragments/api/file.html b/res/template/fragments/api/file.html deleted file mode 100644 index 3e068a3..0000000 --- a/res/template/fragments/api/file.html +++ /dev/null @@ -1,311 +0,0 @@ -{{define "api-file-post"}} -
- POST/file -
-

Description

-

- Upload a file. -

- -

Parameters

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ParamTypeRequiredMaximum SizeDefaultDescription
namestringfalse255 CharactersMultipart file nameName of the file to upload
anonymousbooleanfalseN/AfalseIf the file should be uploaded anonymously
filemultipart filetrue10 000 000 000 BytesnoneMultipart file to upload
- -

Returns

-
HTTP 200: OK
-{
-	"success": true,
-	"id": "abc123" // ID of the newly uploaded file
-}
-
HTTP 422: Unprocessable Entity
-{
-	"success": false,
-	"value": "no_file",
-	"message": "The file does not exist or is empty."
-}
-
HTTP 500: Internal Server Error
-{
-	"success": false,
-	"value": "internal",
-	"message": "An internal server error occurred."
-}
-
HTTP 413: Payload Too Large
-{
-	"success": false,
-	"value": "file_too_large",
-	"message": "The file you tried to upload is too large"
-}
-
HTTP 500: Internal Server Error
-{
-	"success": false,
-	"value": "writing",
-	"message": "Something went wrong while writing the file to disk, the server may be out of storage space."
-}
-
HTTP 413: Payload Too Large
-{
-	"success": false,
-	"value": "name_too_long",
-	"message": "File Name is too long, Max 255 characters allowed."
-}
-
-
-{{end}} -{{define "api-file-id-get"}} -
- GET/file/{id} -
-

Description

-

- Returns the full file associated with the ID. Supports - byte range requests. -

-

- When '?download' is added to the URL the server will send an - attachment header instead of inline rendering, which causes the - browser to show a 'Save File' dialog. -

-

- Warning: If a file is using too much bandwidth it can be rate - limited. The rate limit will be enabled if a file has ten times more - downloads than views. The owner of a file can always download it. - When a file is rate limited the user will need to fill out a captcha - in order to continue downloading the file. The captcha will only - appear on the file viewer page (pixeldrain.com/u/{id}). Rate - limiting has been added to prevent the spread of viruses and to stop - direct linking. -

-

- Pixeldrain also includes a virus scanner. If a virus has been - detected in a file the user will also have to fill in a captcha to - download it. -

-

Parameters

- - - - - - - - - - - - - - - - - - - -
ParamRequiredLocationDescription
idtrueURLID of the file to request
downloadfalseURLSends file attachment instead of inline
-

Returns

-
HTTP 200: OK
-The requested file.
-		
- -
HTTP 404: Not Found
-{
-	"success": false,
-	"value": "not_found",
-	"message": "The entity you requested could not be found"
-}
-
-
HTTP 403: Forbidden
-{
-	"success": false,
-	"value": "file_rate_limited_captcha_required",
-	"message": "This file is using too much bandwidth. For anonymous downloads a captcha is required now. The captcha entry is available on the download page"
-}
-		
-
HTTP 403: Forbidden
-{
-	"success": false,
-	"value": "virus_detected_captcha_required",
-	"message": "This file has been marked as malware by our scanning systems. To avoid infecting other systems through automated downloads we require you to enter a captcha. The captcha entry is available on the download page"
-}
-		
-
-
-{{end}} -{{define "api-file-id-info-get"}} -
- GET/file/{id}/info -
-

Description

-

- Returns information about one or more files. - You can also put a comma separated list of file IDs in - the URL and it will return an array of file info, - instead of a single object. -

-

Parameters

- - - - - - - - - - - - - -
ParamRequiredLocationDescription
idtrueURLID(s) of the file
-

Returns

-
HTTP 200: OK
-{
-	"success": true,
-	"id": "1234abcd",
-	"name": "screenshot.png",
-	"date_upload": 2020-02-04T18:34:05.706801Z,
-	"date_last_view": 2020-02-04T18:34:05.706801Z,
-	"size": 5694837, // Bytes
-	"views" 1234, // Amount of unique file views
-	"bandwidth_used": 1234567890, // Bytes
-	"mime_type" "image/png",
-	"thumbnail_href": "/file/1234abcd/thumbnail" // Link to a thumbnail of this file
-}
-
HTTP 404: Not Found
-{
-	"success": false,
-	"value": "file_not_found"
-}
-
-
-{{end}} -{{define "api-file-id-thumbnail-get"}} -
- GET/file/{id}/thumbnail?width=x&height=x -
-

Description

-

- Returns a PNG thumbnail image representing the file. The thumbnail - image will be 128x128 px by default. You can specify the width and - height with parameters in the URL. The width and height parameters - need to be a multiple of 16. So the allowed values are 16, 32, 48, - 64, 80, 96, 112 and 128. If a thumbnail cannot be generated for the - file you will be redirected to a mime type image of 128x128 px. -

-

Parameters

- - - - - - - - - - - - - - - - - - - - - - - - - -
ParamRequiredLocationDescription
idtrueURLID of the file to get a thumbnail for
widthfalseURLWidth of the thumbnail image
heightfalseURLHeight of the thumbnail image
-

Returns

-

- A PNG image if a thumbnail can be generated. If a thumbnail cannot - be generated you will get a 301 redirect to an image representing - the type of the file. -

-
-
-{{end}} -{{define "api-file-id-delete"}} -
- DELETE/file/{id} -
-

Description

-

- Deletes a file. Only works when the users owns the file. -

-

Parameters

- - - - - - - - - - - - - -
ParamRequiredLocationDescription
idtrueURLID of the file to delete
-

Returns

-
HTTP 200: OK
-{
-	"success": true,
-	"value": "file_deleted",
-	"message": "The file has been deleted."
-}
-
HTTP 404: Not Found
-{
-	"success": false,
-	"value": "file_not_found",
-	"message": "File ID was not found in the database."
-}
-
HTTP 401: Unauthorized
-{
-	"success": false,
-	"value": "unauthorized",
-	"message": "You are not logged in."
-}
-
HTTP 403: Forbidden
-{
-	"success": false,
-	"value": "forbidden",
-	"message": "This is not your file."
-}
-
-
-{{end}} diff --git a/res/template/fragments/api/filesystem.html b/res/template/fragments/api/filesystem.html deleted file mode 100644 index 8079a02..0000000 --- a/res/template/fragments/api/filesystem.html +++ /dev/null @@ -1,162 +0,0 @@ -{{define "api-filesystem-path-post"}} -
- POST/filesystem/{path} -
-

Description

-

- Creates a new directory or uploads a file to an existing directory. -

- -

Parameters

-

- The form parameters must be sent in the order displayed below - for the realtime error checking to work. If 'name' comes after - 'file' it will be ignored. -

- - - - - - - - - - - - - - - - - - - - - -
ParamLocationDescription
typeForm ValuesThe type of node to create, can either be 'directory', or 'file'
nameForm Values - Name of the directory to create, or of file to create. Not - required if 'type' is 'file' -
fileForm Values - Multipart file to upload to the directory. Will be ignored - if 'type' is 'directory' -
- -

Returns

-
HTTP 200: OK
-{
-	"success": true,
-	"id": "abc123" // ID of the newly uploaded file
-}
- todo -
-
-{{end}} -{{define "api-filesystem-path-get"}} -
- GET/filesystem/{path} -
-

Description

-

- Returns information about the requested path. -

-

Parameters

- - - - - - - - - - - - - - - - - - - -
ParamRequiredLocationDescription
pathtrueURLPath to the directory or file to request
downloadfalseURL - If the URL paramater '?download' is passed the requested - file will be downloaded (if it is a file) -
-

Returns

-

When the requested entity is a directory:

-
HTTP 200: OK
-{
-	"success": true,
-	"name": "some dir",
-	"path": "/some dir",
-	"type": "directory",
-	"child_directories": [
-		{
-			"name": "some other directory",
-			"type": "directory",
-			"path": "/some dir/some other directory"
-		}
-	],
-	"child_files": [
-		{
-			"name": "11. Lenny Kravitz - Fly away.ogg",
-			"type": "file",
-			"path": "/some dir/11. Lenny Kravitz - Fly away.ogg"
-		}
-	]
-}
-

When the requested entity is a file:

-
HTTP 200: OK
-{
-	"success": true,
-	"name": "11. Lenny Kravitz - Fly away.ogg",
-	"path": "/some dir/11. Lenny Kravitz - Fly away.ogg",
-	"type": "file",
-	"file_info": {
-		"success": true,
-		"id": "Jf_u5TI9",
-		"name": "11. Lenny Kravitz - Fly away.ogg",
-		"date_upload": "2018-07-04T22:24:48Z",
-		"date_last_view": "2018-07-04T22:24:48Z",
-		"size": 9757269,
-		"views": 0,
-		"mime_type": "application/ogg",
-		"thumbnail_href": "/file/Jf_u5TI9/thumbnail"
-	}
-}
-
-
-{{end}} -{{define "api-filesystem-path-delete"}} -
- DELETE/filesystem/{path} -
-

Description

-

- Deletes a filesystem node. -

-

Parameters

- - - - - - - - - - - - - -
ParamRequiredLocationDescription
pathtrueURLPath of the entity to delete
-

Returns

-
HTTP 200: OK
-{
-	"success": true
-}
-
-
-{{end}} diff --git a/res/template/fragments/api/list.html b/res/template/fragments/api/list.html deleted file mode 100644 index bdd040b..0000000 --- a/res/template/fragments/api/list.html +++ /dev/null @@ -1,180 +0,0 @@ -{{define "api-list-post"}} -
- POST/list -
-

Description

-

- Creates a list of files that can be viewed together on the file - viewer page. -

-

Parameters

-

- POST body should be a JSON object, example below. A list can contain - maximally 10000 files. If you try to add more the request will fail. -

-

Example

-
-{
-	"title": "My beautiful photos", // Defaults to "Pixeldrain List"
-	"anonymous": false / true, // If true this list will not be linked to your user account. Defaults to "false"
-	"files": [ // Ordered array of files to add to the list
-		{
-			"id": "abc123",
-			"description": "First photo of the week, such a beautiful valley"
-		},
-		{
-			"id": "123abc",
-			"description": "The week went by so quickly, here's a photo from the plane back"
-		}
-	]
-}
-
-

Returns

-
HTTP 200: OK
-{
-	"success": true,
-	"id": "yay137" // ID of the newly created list
-}
-
-
HTTP 422: Unprocessable Entity
-{
-	"success": false,
-	"value": "list_file_not_found",
-	"message": "File Oh42No was not found in the database.",
-	"extra": {
-		"file_not_found": "0h42No" // The file you tried to add with this ID does not exist
-	}
-}
-
-
HTTP 413: Payload too large
-{
-	"success": false,
-	"value": "too_many_files",
-	"message": "This list contains too many files, max 10000 allowed."
-}
-
-
HTTP 422: Unprocessable Entity
-{
-	"success": false,
-	"value": "json_parse_failed",
-	"message": "The JSON object in the request body could not be read."
-}
-
-
HTTP 413: Payload too large
-{
-	"success": false,
-	"value": "title_too_long",
-	"message": "The title of this list is too long, max 300 characters allowed."
-}
-
-
HTTP 413: Payload too large
-{
-	"success": false,
-	"value": "description_too_long",
-	"message": "The description of one of the files in the list is too long, max 3000 characters allowed."
-}
-
-
HTTP 422: Unprocessable Entity
-{
-	"success": false,
-	"value": "cannot_create_empty_list",
-	"message": "You cannot make a list with no files."
-}
-
-
-
-{{end}} -{{define "api-list-get"}} -
- GET/list/{id} -
-

Description

-

- Returns information about a file list and the files in it. -

-

Parameters

- - - - - - - - - - - - - -
ParamRequiredLocationDescription
idtrueURLID of the list
-

Returns

-

- The API will return some basic information about every file. - Every file also has a "detail_href" field which contains a URL - to the info API of the file. Follow that link to get more - information about the file like size, checksum, mime type, etc. - The address is relative to the API URL and should be appended to - the end. -

-
HTTP 200: OK
-{
-	"success": true,
-	"id": "L8bhwx",
-	"title": "Rust in Peace",
-	"date_created": 2020-02-04T18:34:13.466276Z,
-	"files": [
-		// These structures are the same as the file info response, except for the detail_href and description fields
-		{
-			"detail_href": "/file/_SqVWi/info",
-			"description": "",
-			"success": true,
-			"id": "_SqVWi",
-			"name": "01 Holy Wars... The Punishment Due.mp3",
-			"size": 123456,
-			"date_created": 2020-02-04T18:34:13.466276Z,
-			"date_last_view": 2020-02-04T18:34:13.466276Z,
-			"mime_type": "audio/mp3",
-			"views": 1,
-			"bandwidth_used": 1234567890,
-			"thumbnail_href": "/file/_SqVWi/thumbnail"
-		},
-		{
-			"detail_href": "/file/RKwgZb/info",
-			"description": "",
-			"success": true,
-			"id": "RKwgZb",
-			"name": "02 Hangar 18.mp3",
-			"size": 123456,
-			"date_created": 2020-02-04T18:34:13.466276Z,
-			"date_last_view": 2020-02-04T18:34:13.466276Z,
-			"mime_type": "audio/mp3",
-			"views": 2,
-			"bandwidth_used": 1234567890,
-			"thumbnail_href": "/file/RKwgZb/thumbnail"
-		},
-		{
-			"detail_href": "/file/DRaL_e/info",
-			"description": "",
-			"success": true,
-			"id": "DRaL_e",
-			"name": "03 Take No Prisoners.mp3",
-			"size": 123456,
-			"date_created": 2020-02-04T18:34:13.466276Z,
-			"date_last_view": 2020-02-04T18:34:13.466276Z,
-			"mime_type": "audio/mp3",
-			"views": 3,
-			"bandwidth_used": 1234567890,
-			"thumbnail_href": "/file/DRaL_e/thumbnail"
-		}
-	]
-}
-
-
HTTP 404: Not Found
-{
-	"success": false,
-	"value": "list_not_found",
-}
-
-
-
-{{end}} diff --git a/res/template/fragments/markdown_wrapper.html b/res/template/fragments/markdown_wrapper.html new file mode 100644 index 0000000..3ede9ff --- /dev/null +++ b/res/template/fragments/markdown_wrapper.html @@ -0,0 +1,18 @@ +{{define "markdown_wrapper"}} + + + {{template "meta_tags" .Title}} + {{template "user_style" .}} + + + + {{template "page_top" .}} +

{{.Title}}

+
+ {{.Other}} +
+ {{template "page_bottom" .}} + {{template "analytics"}} + + +{{end}} diff --git a/webcontroller/web_controller.go b/webcontroller/web_controller.go index 0ba6796..6b9ef8a 100644 --- a/webcontroller/web_controller.go +++ b/webcontroller/web_controller.go @@ -1,8 +1,10 @@ package webcontroller import ( + "bytes" "errors" "fmt" + "html/template" "net/http" "os" "strings" @@ -12,6 +14,7 @@ import ( "github.com/Fornaxian/log" "github.com/google/uuid" "github.com/julienschmidt/httprouter" + blackfriday "github.com/russross/blackfriday/v2" ) // WebController controls how requests are handled and makes sure they have @@ -100,16 +103,16 @@ func New( }{ // General navigation {GET, "" /* */, wc.serveTemplate("home", false)}, - {GET, "api" /* */, wc.serveTemplate("apidoc", false)}, + {GET, "api" /* */, wc.serveMarkdown("apidoc.md", false)}, {GET, "history" /* */, wc.serveTemplate("history_cookies", false)}, {GET, "u/:id" /* */, wc.serveFileViewer}, {GET, "u/:id/preview" /**/, wc.serveFilePreview}, {GET, "l/:id" /* */, wc.serveListViewer}, {GET, "s/:id" /* */, wc.serveSkynetViewer}, {GET, "t" /* */, wc.serveTemplate("paste", false)}, - {GET, "donation" /* */, wc.serveTemplate("donation", false)}, + {GET, "donation" /* */, wc.serveMarkdown("donation.md", false)}, {GET, "widgets" /* */, wc.serveTemplate("widgets", false)}, - {GET, "about" /* */, wc.serveTemplate("about", false)}, + {GET, "about" /* */, wc.serveMarkdown("about.md", false)}, {GET, "appearance" /* */, wc.serveTemplate("appearance", false)}, // User account pages @@ -171,6 +174,65 @@ func (wc *WebController) serveTemplate( } } +func (wc *WebController) serveMarkdown(tpl string, requireAuth bool) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + var err error + var tpld = wc.newTemplateData(w, r) + if requireAuth && !tpld.Authenticated { + http.Redirect(w, r, "/login", http.StatusSeeOther) + return + } + + // Execute the raw markdown template and save the result in a buffer + var tplBuf bytes.Buffer + if err = wc.templates.Get().ExecuteTemplate(&tplBuf, tpl, tpld); err != nil { + log.Error("Error executing template '%s': %s", tpl, err) + return + } + + // Parse the markdown document and save the resulting HTML in a buffer + renderer := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{ + Flags: blackfriday.CommonHTMLFlags, + }) + + // We parse the markdown document, walk through the nodes. Extract the + // title of the document, and the rest of the nodes are rendered like + // normal + var mdBuf bytes.Buffer + var inHeader = false + blackfriday.New( + blackfriday.WithRenderer(renderer), + blackfriday.WithExtensions(blackfriday.CommonExtensions), + ).Parse( + tplBuf.Bytes(), + ).Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + // Capture the title of the document so we can put it at the top of + // the template and in the metadata. When entering a h1 node the + // next node will be the title of the document. Save that value + if node.Type == blackfriday.Heading && node.HeadingData.Level == 1 { + inHeader = entering + return blackfriday.GoToNext + } + if inHeader { + tpld.Title = string(node.Literal) + log.Info(string(node.Literal)) + return blackfriday.GoToNext + } + + return renderer.RenderNode(&mdBuf, node, entering) + }) + + // Pass the buffer's parsed contents to the wrapper template + tpld.Other = template.HTML(mdBuf.Bytes()) + + // Execute the wrapper template + err = wc.templates.Get().ExecuteTemplate(w, "markdown_wrapper", tpld) + if err != nil && !strings.Contains(err.Error(), "broken pipe") { + log.Error("Error executing template '%s': %s", tpl, err) + } + } +} + func (wc *WebController) serveFile(path string) httprouter.Handle { return func( w http.ResponseWriter,