diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b0d22d81..ef7601a3 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to Spacebin -Hey! First off: Thanks for deciding to contribute to Spirit, but, just before you get started we need to go over a few things. +Hey! First off: Thanks for deciding to contribute to Spacebin, but, just before you get started we need to go over a few things. When contributing to Spirit, please keep in mind we have a few fundamental guidelines that you must abide by: @@ -10,6 +10,9 @@ When contributing to Spirit, please keep in mind we have a few fundamental guide * Make thoughtful decisions about Pull Requests and Issues. * Follow the [Code of Conduct](code_of_conduct.md). +> [!WARNING] +> Sometimes in this document we will refer to Spacebin as Spirit. Originally, Spirit was the name of the Spacebin server. The projects have since been merged and they are now the same thing. Eventually, all references to Spirit will be replaced. + ## Setting up your environment This section covers installing and configuring your development environment for contributing to Spirit. @@ -18,23 +21,27 @@ The one thing this section won't cover is installing [Git](https://git-scm.org), ### Installing Golang -Since Spirit is written in Go, we're going to need it in our installed in our environments. Obviously, you can feel free to skip this part if already completed. +Since Spacebin is written in Go, we're going to need it in our installed in our environments. Obviously, you can feel free to skip this part if already completed. The steps for installing Go can drastically differ operating system to operating system; So, you should really be looking for instructions from the Go [documentation pages](https://golang.org/doc/install). -You'll need **at least** Go 1.14. +You'll need **at least** Go 1.22.4. -### Installing Magefile +### Makefile -We use Magefile as our build system — a make/rake-like build tool using Go. Installation is easy, just run these three commands: +We use [GNU make](https://www.gnu.org/software/make/manual/make.html) to make it easier to run the software when developing: + * If you use BGNU Linux or macOS, make is most likely already installed. + * If you use Windows, you will need to either download [Make for Windows](https://gnuwin32.sourceforge.net/install.html) + * `winget install -e --id GnuWin32.Make` or `choco install make` or ` -```sh -$ git clone https://github.com/magefile/mage -$ cd mage -$ go run bootstrap.go -``` +#### Makefile overview -You can run these commands in any directory of your choice. +* `make spacebin`: Build a new Spacebin binary. +* `make clean`: Remove old binaries. +* `make run`: Build a new Spacebin binary and run it. +* `make format`: Format source code with `go fmt` +* `make test`: Run tests. +* `make coverage`: Run tests and generate coverage files. ### Cloning the Git repository @@ -50,13 +57,28 @@ Installing dependencies is quite easily done with Go, especially so ever since t #### Building and running the program -... +You can use the `make run` command to build and run the Spacebin binary. However, running this command alone will cause an error. You need to provide a database for Spacebin to use via the `SPIRIT_CONNECTION_URI` environment variable. + +Currently you have two options for a database: +* **SQLite**: `file://spacebin.db` or `sqlite://spacebin.db` +* **PostgreSQL**: [`postgres://user@localhost:5432/spacebin`](https://stackoverflow.com/questions/3582552/what-is-the-format-for-the-postgresql-connection-string-url#20722229) +* MySQL and more are in development. + +For development, it is easiest to use SQLite. However, Postgres should always be used in production. + +With that being said, use the following to run Spacebin for developent: +```sh +$ SPIRIT_CONNECTION_URI="sqlite://spacebin.db" make run +``` + +> [!IMPORTANT] +> You will need to rerun this command after every change. ### Make your changes -Go, make your changes to Spirit. Just make sure to follow our style guidelines and conventions and to rebuild and test your program with each change. +Alright! Go make your changes to Spacebin! Just make sure to follow our style guidelines and conventions and to rebuild and test your program with each change. -Additionally, once your done making changes you need to commit your code. Committing your code is quite easily done, just run the following two commands: +Once your done with a change, commit your code. You should do so after every feature you add or bug you fix to keep your commits small and tidy. Committing your code is quite easily done, just run the following two commands: ```sh $ git add . @@ -71,9 +93,9 @@ In order for your changes to be included in the next release you need to create Generally though, the process goes like this: -* First, Above the file directory on the main page, click the "Pull request" button. -* Second, In the "base branch" drop-down menu, select the branch of the upstream Spirit repository to merge changes into. This needs to be the "develop" branch, otherwise your PR will not be merged. -* Third, In the "head branch" drop-down, select the "develop" branch +1. Above the file directory on the main page, click the "Pull request" button. +2. In the "base branch" drop-down menu, select the branch of the upstream Spirit repository to merge changes into. This needs to be the "develop" branch, otherwise your PR will not be merged. +3. In the "head branch" drop-down, select the "develop" branch ## Styling of Code @@ -82,7 +104,8 @@ Generally though, the process goes like this: * Prefer **readability and simplicity over efficiency**. * Always run your code through **`go fmt`**. * Attempt to **not** let any line be **longer than 80 characters**. +* **Test** your code **before** committing changes. ## Commit Guidelines -... +Follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary). diff --git a/README.md b/README.md index c65117a8..de3f3881 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

spacebin - hastebin fork focused on stability and maintainability

@@ -11,27 +11,34 @@ [![codecov](https://codecov.io/gh/lukewhrit/spacebin/graph/badge.svg?token=NNZDS74DB1)](https://codecov.io/gh/lukewhrit/spacebin) [![GitHub license](https://img.shields.io/github/license/lukewhrit/spacebin?color=%20%23e34b4a&logoColor=%23000000)](LICENSE) [![Build](https://github.com/lukewhrit/spacebin/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/lukewhrit/spacebin/actions/workflows/build.yml) [![Go report card](https://goreportcard.com/badge/github.com/lukewhrit/spacebin)](https://goreportcard.com/report/github.com/lukewhrit/spacebin) -Spacebin is a modern Pastebin server implemented in Go and maintained by Luke Whritenour. It is capable of serving notes, novels, code, or any other form of text! Spacebin was designed to be fast and reliable, avoiding the problems of many current pastebin servers. Spacebin features JavaScript-based text highlighting, but works completely fine with JS disabled. Besides text highlighting, we have many more features in the works. It is entirely self-hostable, and available in a Docker image. +Spacebin is a modern Pastebin server implemented in Go and is capable of serving notes, novels, code, or any other form of text. + +Spacebin was designed to be fast and reliable, avoiding the problems of many current pastebin servers. Spacebin features JavaScript-based text highlighting, but works completely fine with JS disabled. Besides text highlighting, we have many more features in the works. It is entirely self-hostable, and available in a Docker image. Pastebins are a type of online content storage service where users can store plain text document, e.g. program source code. For more information and the history of Pastebin see Wikipedia's [article on them](https://en.wikipedia.org/wiki/Pastebin). +> [!IMPORTANT] +> **Try our public online version at [https://spaceb.in](https://spaceb.in)**! + **Features:** -- [x] 99% self-contained: only requires Postgres to run. -- [x] Raw text and file uploading +- [x] 99% self-contained: only requires a database to run. +- [x] Raw text and code uploading - [x] Phrase and random string identifiers. -- [x] Custom documents that are always available. +- [x] Custom named documents that are always available. - [x] Configurable ratelimiting, expiration, compression, etc. - [x] Modern, JavaScript-free user interface - [x] Syntax highlighting for all the most popular languages and Raw text mode +- [x] SQLite and PostgreSQL Support +- [x] Basic Auth for private instances - [ ] Password-protected encrypted pastes -- [x] SQLite Support - [ ] Paste collections - [ ] Reader view mode (Markdown is formatted and word wrapping is enabled) - [ ] QR Codes -- [ ] Image uploading -> [!TIP] > **Try our public online version at [https://spaceb.in](https://spaceb.in)**! +**Vote on future features: [Image/file uploading](https://github.com/lukewhrit/spacebin/discussions/446), [Account system](https://github.com/lukewhrit/spacebin/discussions/447)** + +Looking for a URL shortener too? Try [redeyes](https://github.com/lukewhrit/redeyes). ## Table of Contents @@ -40,6 +47,7 @@ Pastebins are a type of online content storage service where users can store pla - [Documentation](#documentation) - [Self-hosting](#self-hosting) - [Using Docker](#using-docker) + - [Docker Compose](#docker-compose) - [Manually](#manually) - [Environment Variables](#environment-variables) - [Database Connection URI](#database-connection-uri) @@ -53,6 +61,9 @@ Pastebins are a type of online content storage service where users can store pla ## Documentation +> [!TIP] +> Need support? Visit our [Discussions](https://github.com/lukewhrit/spacebin/discussions) tab to get help from the community. + ### Self-hosting #### Using Docker @@ -60,7 +71,36 @@ Pastebins are a type of online content storage service where users can store pla ```sh # Pull and run docker image on port 80 $ sudo docker pull spacebinorg/spirit -$ sudo docker run -d -p 80:9000 spacebinorg/spirit +$ sudo docker run -d -e SPIRIT_CONNECTION_URI="sqlite://database.sqlite" -p 80:9000 spacebinorg/spirit +``` + +#### Docker Compose + +Use the following config file to host Spacebin via Docker Compose: + +```yml +services: + spacebin: + image: spacebinorg/spirit:latest + restart: always + environment: + - SPIRIT_CONNECTION_URI=postgres://spacebin:password@postgres:5432/spacebin?sslmode=disable + ports: + - 9000:9000 + depends_on: + - postgres + postgres: + image: postgres:16.3-alpine + restart: always + environment: + - POSTGRES_USER=spacebin + - POSTGRES_PASSWORD=password + - POSTGRES_DB=spacebin + volumes: + - postgres:/var/lib/postgresql/data + +volumes: + postgres: ``` #### Manually @@ -131,7 +171,7 @@ curl -v -F content="Hello, world!" https://spaceb.in/ | jq payload.id **To upload from a file:** ```sh -curl -v -F content=@helloworld.txt https://spaceb.in/ | jq payload.id +curl -v -F content="$(cat helloworld.txt) https://spaceb.in/ | jq payload.id ``` ### API @@ -181,7 +221,7 @@ There are three primary API routes to: create a document, fetch a documents text - Returns a `plain/text` file containing the content of the document. > [!TIP] -> There are two additional non-API routes that are documented: `/ping`: returns a 200 OK if the service is online, and `/config`: returns a JSON body with the instances configuration settings. +> There are two additional non-API routes: `/ping`: returns a 200 OK if the service is online, and `/config`: returns a JSON body with the instances configuration settings. ## Credits diff --git a/go.mod b/go.mod index e37acd15..8d73617a 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/caarlos0/env/v9 v9.0.0 github.com/go-chi/chi/v5 v5.1.0 github.com/go-chi/cors v1.2.1 - github.com/go-chi/httprate v0.12.1 + github.com/go-chi/httprate v0.14.1 github.com/go-ozzo/ozzo-validation/v4 v4.3.0 github.com/lib/pq v1.10.9 github.com/lukewhrit/phrase v1.0.0 @@ -22,7 +22,6 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - golang.org/x/net v0.28.0 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/go.sum b/go.sum index c29d816c..d37cd66c 100644 --- a/go.sum +++ b/go.sum @@ -24,11 +24,13 @@ github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= -github.com/go-chi/httprate v0.12.1 h1:55l3IWrPcipqKb72yBzH+grF51z5w+2Bb/Qmu1bos/E= -github.com/go-chi/httprate v0.12.1/go.mod h1:TUepLXaz/pCjmCtf/obgOQJ2Sz6rC8fSf5cAt5cnTt0= +github.com/go-chi/httprate v0.14.1 h1:EKZHYEZ58Cg6hWcYzoZILsv7ppb46Wt4uQ738IRtpZs= +github.com/go-chi/httprate v0.14.1/go.mod h1:TUepLXaz/pCjmCtf/obgOQJ2Sz6rC8fSf5cAt5cnTt0= github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -49,7 +51,6 @@ github.com/lukewhrit/phrase v1.0.0/go.mod h1:599Lf9xFuahn78B7fYvmIkD8inCDBAOJzAE github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -70,27 +71,33 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/exp v0.0.0-20230807204917-050eac23e9de h1:l5Za6utMv/HsBWWqzt4S8X17j+kt1uVETUX5UFhn2rE= -golang.org/x/exp v0.0.0-20230807204917-050eac23e9de/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA= golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= +modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= +modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= +modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= @@ -99,6 +106,10 @@ modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= diff --git a/internal/server/create.go b/internal/server/create.go index 5cc1ad9c..d262aa22 100644 --- a/internal/server/create.go +++ b/internal/server/create.go @@ -19,43 +19,55 @@ package server import ( "fmt" "net/http" + "strings" "github.com/lukewhrit/spacebin/internal/util" ) -func createDocument(s *Server, w http.ResponseWriter, r *http.Request) string { +// createDocument handles the shared logic between the CreateDocument and StaticCreateDocument handlers. +func createDocument(s *Server, w http.ResponseWriter, r *http.Request) (string, error) { // Parse body from HTML request body, err := util.HandleBody(s.Config.MaxSize, r) if err != nil { util.WriteError(w, http.StatusInternalServerError, err) - return "" + return "", err } // Validate fields of body if err := util.ValidateBody(s.Config.MaxSize, body); err != nil { - util.WriteError(w, http.StatusBadRequest, err) - return "" + return "", fmt.Errorf("bad request: %v", err) } - // Add Document object to database + // Generate ID for document id := util.GenerateID(s.Config.IDType, s.Config.IDLength) + // Add document in database if err := s.Database.CreateDocument( r.Context(), id, body.Content, ); err != nil { - util.WriteError(w, http.StatusInternalServerError, err) - return "" + return "", err } - return id + return id, nil } func (s *Server) CreateDocument(w http.ResponseWriter, r *http.Request) { // Create document, then pull it from the database - id := createDocument(s, w, r) + id, err := createDocument(s, w, r) + + if err != nil { + if strings.Contains(err.Error(), "bad request:") { + util.WriteError(w, http.StatusBadRequest, err) + return + } else { + util.WriteError(w, http.StatusInternalServerError, err) + return + } + } + document, err := s.Database.GetDocument(r.Context(), id) if err != nil { @@ -72,13 +84,25 @@ func (s *Server) CreateDocument(w http.ResponseWriter, r *http.Request) { func (s *Server) StaticCreateDocument(w http.ResponseWriter, r *http.Request) { // Create document, then pull it from the database - id := createDocument(s, w, r) + id, err := createDocument(s, w, r) + + if err != nil { + if strings.Contains(err.Error(), "bad request:") { + util.RenderError(&resources, w, http.StatusBadRequest, err) + return + } else { + util.RenderError(&resources, w, http.StatusInternalServerError, err) + return + } + } + document, err := s.Database.GetDocument(r.Context(), id) if err != nil { - util.WriteError(w, http.StatusInternalServerError, err) + util.RenderError(&resources, w, http.StatusInternalServerError, err) return } + // Redirect to document view page http.Redirect(w, r, fmt.Sprintf("/%s", document.ID), http.StatusMovedPermanently) }