Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Chiefs
ChiefSend2
Commits
ce0ac207
Commit
ce0ac207
authored
Mar 22, 2021
by
Lukas Böhm
🎱
Browse files
new error handling
parent
a1b0d672
Changes
2
Hide whitespace changes
Inline
Side-by-side
api/api.go
View file @
ce0ac207
...
...
@@ -7,7 +7,6 @@ import (
"github.com/google/uuid"
"github.com/gorilla/mux"
"github.com/rs/cors"
"gorm.io/driver/sqlserver"
"gorm.io/gorm"
"io/ioutil"
"log"
...
...
@@ -16,304 +15,251 @@ import (
"path/filepath"
)
type
HTTPError
struct
{
Error
error
Message
string
Code
int
}
type
endpointREST
func
(
http
.
ResponseWriter
,
*
http
.
Request
)
*
HTTPError
func
(
fn
endpointREST
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
if
e
:=
fn
(
w
,
r
);
e
!=
nil
{
// e is *HTTPError, not os.Error.
fmt
.
Errorf
(
"Error (%s): %s - %i"
,
e
.
Error
.
Error
(),
e
.
Message
,
e
.
Code
)
if
e
.
Code
==
401
{
w
.
Header
()
.
Set
(
"WWW-Authenticate"
,
`Basic realm="Please enter the password"`
)
}
http
.
Error
(
w
,
e
.
Message
,
e
.
Code
)
}
}
/////////////////////////////////
//////////// routes /////////////
/////////////////////////////////
func
AllShares
(
w
http
.
ResponseWriter
,
_
*
http
.
Request
)
{
func
AllShares
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
*
HTTPError
{
fmt
.
Println
(
"AllShares"
)
db
,
err
:=
GetDatabase
()
//return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't get database"
,
500
}
}
var
shares
[]
Share
err
=
db
.
Where
(
"is_public = ? AND is_temporary = 0"
,
1
)
.
Find
(
&
shares
)
.
Error
// return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
return
return
&
HTTPError
{
err
,
"Can't fetch data"
,
500
}
}
// return 200
SendJSON
(
w
,
shares
)
return
nil
}
func
GetShare
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
GetShare
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
*
HTTPError
{
fmt
.
Println
(
"Get Share"
)
vars
:=
mux
.
Vars
(
r
)
db
,
err
:=
GetDatabase
()
//return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't get database"
,
500
}
}
var
share
Share
err
=
db
.
Preload
(
"Attachments"
)
.
Where
(
"ID = ?"
,
vars
[
"id"
])
.
First
(
&
share
)
.
Error
// return 404
if
errors
.
Is
(
err
,
gorm
.
ErrRecordNotFound
)
{
w
.
WriteHeader
(
http
.
StatusNotFound
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Record not found"
,
404
}
}
//return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't fetch data"
,
500
}
}
// return 424
if
share
.
IsTemporary
==
true
{
w
.
WriteHeader
(
http
.
StatusFailedDependency
)
return
return
&
HTTPError
{
err
,
"Share is not finalized"
,
424
}
}
//return 401
sid
,
pass
,
_
:=
r
.
BasicAuth
()
if
sid
!=
share
.
ID
.
String
()
{
w
.
WriteHeader
(
http
.
StatusUnauthorized
)
w
.
Header
()
.
Set
(
"WWW-Authenticate"
,
`Basic realm="Please enter the password"`
)
w
.
Write
([]
byte
(
"401 Unauthorized
\n
"
))
return
return
&
HTTPError
{
err
,
"wrong username"
,
401
}
}
if
pass
!=
share
.
Password
{
w
.
WriteHeader
(
http
.
StatusUnauthorized
)
w
.
Header
()
.
Set
(
"WWW-Authenticate"
,
`Basic realm="Please enter the password"`
)
w
.
Write
([]
byte
(
"401 Unauthorized
\n
"
))
return
return
&
HTTPError
{
err
,
"wrong password"
,
401
}
}
// return 200
SendJSON
(
w
,
share
)
return
nil
}
func
DownloadFile
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
DownloadFile
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
*
HTTPError
{
fmt
.
Println
(
"Download file"
)
vars
:=
mux
.
Vars
(
r
)
db
,
err
:=
GetDatabase
()
//return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't get database"
,
500
}
}
var
att
Attachment
err
=
db
.
Where
(
"id = ?"
,
vars
[
"att"
])
.
First
(
&
att
)
.
Error
// return 404
if
errors
.
Is
(
err
,
gorm
.
ErrRecordNotFound
)
{
w
.
WriteHeader
(
http
.
StatusNotFound
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Record not found"
,
404
}
}
//return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't fetch data"
,
500
}
}
var
share
Share
err
=
db
.
Where
(
"id = ?"
,
att
.
ShareID
)
.
First
(
&
share
)
.
Error
//return 500
if
errors
.
Is
(
err
,
gorm
.
ErrRecordNotFound
)
{
return
&
HTTPError
{
err
,
"Record not found"
,
404
}
}
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't fetch data"
,
500
}
}
//return 401
sid
,
pass
,
_
:=
r
.
BasicAuth
()
if
sid
!=
share
.
ID
.
String
()
{
w
.
WriteHeader
(
http
.
StatusUnauthorized
)
w
.
Header
()
.
Set
(
"WWW-Authenticate"
,
`Basic realm="Please enter the password"`
)
w
.
Write
([]
byte
(
"401 Unauthorized
\n
"
))
return
return
&
HTTPError
{
err
,
"wrong username"
,
401
}
}
if
pass
!=
share
.
Password
{
w
.
WriteHeader
(
http
.
StatusUnauthorized
)
w
.
Header
()
.
Set
(
"WWW-Authenticate"
,
`Basic realm="Please enter the password"`
)
w
.
Write
([]
byte
(
"401 Unauthorized
\n
"
))
return
return
&
HTTPError
{
err
,
"wrong password"
,
401
}
}
// return 200
w
.
Header
()
.
Set
(
"Content-Disposition"
,
fmt
.
Sprintf
(
"attachment; filename=%s"
,
att
.
Filename
))
http
.
ServeFile
(
w
,
r
,
filepath
.
Join
(
config
.
mediaDir
,
"data"
,
vars
[
"id"
],
vars
[
"att"
]))
return
nil
}
func
OpenShare
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
OpenShare
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
*
HTTPError
{
fmt
.
Println
(
"OpenShare"
)
db
,
err
:=
GetDatabase
()
//return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't get database"
,
500
}
}
// parse body
reqBody
,
err
:=
ioutil
.
ReadAll
(
r
.
Body
)
// return 400
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusBadRequest
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Request does not contain a valid body"
,
400
}
}
// parse in json
var
newShare
Share
err
=
json
.
Unmarshal
(
reqBody
,
&
newShare
)
// return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't parse data"
,
500
}
}
// create temporary db entries
err
=
db
.
Create
(
&
newShare
)
.
Error
newShare
.
IsTemporary
=
true
db
.
Save
(
&
newShare
)
// return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't save data"
,
500
}
}
// create temporary dir
err
=
os
.
MkdirAll
(
filepath
.
Join
(
config
.
mediaDir
,
"temp"
,
newShare
.
ID
.
String
()),
os
.
ModePerm
)
// return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't create directory"
,
500
}
}
// return 201
w
.
WriteHeader
(
http
.
StatusCreated
)
SendJSON
(
w
,
newShare
)
return
nil
}
func
CloseShare
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
CloseShare
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
*
HTTPError
{
fmt
.
Println
(
"CloseShare"
)
vars
:=
mux
.
Vars
(
r
)
db
,
err
:=
GetDatabase
()
//return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't get database"
,
500
}
}
// get stuff
var
share
Share
err
=
db
.
Where
(
"id = ?"
,
vars
[
"id"
])
.
First
(
&
share
)
.
Error
// return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
if
errors
.
Is
(
err
,
gorm
.
ErrRecordNotFound
)
{
return
&
HTTPError
{
err
,
"Record not found"
,
404
}
}
// return 424
if
share
.
IsTemporary
==
false
{
w
.
WriteHeader
(
http
.
StatusFailedDependency
)
return
if
err
!=
nil
{
return
&
HTTPError
{
err
,
"Can't fetch data"
,
500
}
}
// move files to permanent location
oldPath
:=
filepath
.
Join
(
config
.
mediaDir
,
"temp"
,
vars
[
"id"
])
newPath
:=
filepath
.
Join
(
config
.
mediaDir
,
"data"
,
vars
[
"id"
])
err
=
os
.
Rename
(
oldPath
,
newPath
)
// return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't move directory"
,
500
}
}
// set stuff permanent
share
.
IsTemporary
=
false
err
=
db
.
Save
(
&
share
)
.
Error
// return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't edit data"
,
500
}
}
// return 200
SendJSON
(
w
,
share
)
return
nil
}
func
UploadAttachment
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
UploadAttachment
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
*
HTTPError
{
fmt
.
Println
(
"UploadTest"
)
vars
:=
mux
.
Vars
(
r
)
db
,
err
:=
GetDatabase
()
//return 500
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Can't get database"
,
500
}
}
// Parse file from body
err
=
r
.
ParseMultipartForm
(
config
.
chunkSize
)
// Maximum 10 MB in RAM
// return 400
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusBadRequest
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Request does not contain a valid body"
,
400
}
}
file
,
handler
,
err
:=
r
.
FormFile
(
"files"
)
// return 400
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusBadRequest
)
w
.
Write
([]
byte
(
err
.
Error
()))
return
return
&
HTTPError
{
err
,
"Request does not contain a valid body"
,
400
}
}
defer
file
.
Close
()
// TODO fehlerbehandlung
// add db entry TODO fehlerbehandlung für die ganze transaction
db
.
Begin
()
var
att
Attachment
sid
,
err
:=
uuid
.
Parse
(
vars
[
"id"
])
if
err
!=
nil
{
log
.
Fatal
(
err
)
{
// add db entry TODO fehlerbehandlung für die ganze transaction
db
.
Begin
()
sid
,
err
:=
uuid
.
Parse
(
vars
[
"id"
])
if
err
!=
nil
{
fmt
.
Println
(
err
)
}
att
.
ShareID
=
sid
att
.
Filename
=
handler
.
Filename
att
.
Filesize
=
handler
.
Size
db
.
Create
(
&
att
)
// save file
fileBytes
,
err
:=
ioutil
.
ReadAll
(
file
)
if
err
!=
nil
{
fmt
.
Println
(
err
)
}
err
=
ioutil
.
WriteFile
(
filepath
.
Join
(
"media"
,
"temp"
,
vars
[
"id"
],
att
.
ID
.
String
()),
fileBytes
,
os
.
ModePerm
)
if
err
!=
nil
{
fmt
.
Println
(
err
)
db
.
Rollback
()
}
db
.
Commit
()
}
att
.
ShareID
=
sid
att
.
Filename
=
handler
.
Filename
att
.
Filesize
=
handler
.
Size
db
.
Create
(
&
att
)
// save file
fileBytes
,
err
:=
ioutil
.
ReadAll
(
file
)
if
err
!=
nil
{
fmt
.
Println
(
err
)
}
err
=
ioutil
.
WriteFile
(
filepath
.
Join
(
"media"
,
"temp"
,
vars
[
"id"
],
att
.
ID
.
String
()),
fileBytes
,
os
.
ModePerm
)
if
err
!=
nil
{
fmt
.
Println
(
err
)
db
.
Rollback
()
}
db
.
Commit
()
//return 201
w
.
WriteHeader
(
http
.
StatusCreated
)
SendJSON
(
w
,
att
)
return
nil
}
...
...
@@ -324,28 +270,19 @@ func ConfigureRoutes() {
router
:=
mux
.
NewRouter
()
.
StrictSlash
(
true
)
handler
:=
cors
.
Default
()
.
Handler
(
router
)
router
.
Handle
Func
(
"/shares"
,
AllShares
)
.
Methods
(
"GET"
)
router
.
Handle
Func
(
"/shares"
,
OpenShare
)
.
Methods
(
"POST"
)
router
.
Handle
(
"/shares"
,
endpointREST
(
AllShares
)
)
.
Methods
(
"GET"
)
router
.
Handle
(
"/shares"
,
endpointREST
(
OpenShare
)
)
.
Methods
(
"POST"
)
router
.
Handle
Func
(
"/share/{id}"
,
GetShare
)
.
Methods
(
"GET"
)
router
.
Handle
Func
(
"/share/{id}"
,
CloseShare
)
.
Methods
(
"POST"
)
router
.
Handle
(
"/share/{id}"
,
endpointREST
(
GetShare
)
)
.
Methods
(
"GET"
)
router
.
Handle
(
"/share/{id}"
,
endpointREST
(
CloseShare
)
)
.
Methods
(
"POST"
)
router
.
Handle
Func
(
"/share/{id}/attachments"
,
UploadAttachment
)
.
Methods
(
"POST"
)
router
.
Handle
(
"/share/{id}/attachments"
,
endpointREST
(
UploadAttachment
)
)
.
Methods
(
"POST"
)
router
.
Handle
Func
(
"/share/{id}/attachment/{att}"
,
DownloadFile
)
.
Methods
(
"GET"
)
router
.
Handle
(
"/share/{id}/attachment/{att}"
,
endpointREST
(
DownloadFile
)
)
.
Methods
(
"GET"
)
log
.
Fatal
(
http
.
ListenAndServe
(
":6969"
,
handler
))
}
func
GetDatabase
()(
*
gorm
.
DB
,
error
)
{
dsn
:=
os
.
Getenv
(
"DATABASE_URI"
)
db
,
err
:=
gorm
.
Open
(
sqlserver
.
Open
(
dsn
),
&
gorm
.
Config
{})
if
err
!=
nil
{
return
nil
,
errors
.
New
(
"failed to connect to database"
)
}
return
db
,
nil
}
func
SendJSON
(
w
http
.
ResponseWriter
,
res
interface
{})
{
w
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
err
:=
json
.
NewEncoder
(
w
)
.
Encode
(
res
)
...
...
api/database.go
View file @
ce0ac207
package
main
import
(
"errors"
"github.com/google/uuid"
"gorm.io/driver/sqlserver"
"gorm.io/gorm"
"
log
"
"
os
"
"time"
)
...
...
@@ -31,19 +33,11 @@ type Attachment struct {
}
func
(
att
*
Attachment
)
BeforeCreate
(
scope
*
gorm
.
DB
)
error
{
uid
,
err
:=
uuid
.
NewRandom
()
func
GetDatabase
()(
*
gorm
.
DB
,
error
)
{
dsn
:=
os
.
Getenv
(
"DATABASE_URI"
)
db
,
err
:=
gorm
.
Open
(
sqlserver
.
Open
(
dsn
),
&
gorm
.
Config
{})
if
err
!=
nil
{
log
.
Fatal
(
err
)
return
nil
,
errors
.
New
(
"failed to connect to database"
)
}
att
.
ID
=
uid
return
nil
}
func
(
sh
*
Share
)
BeforeCreate
(
scope
*
gorm
.
DB
)
error
{
uid
,
err
:=
uuid
.
NewRandom
()
if
err
!=
nil
{
log
.
Fatal
(
err
)
}
sh
.
ID
=
uid
return
nil
return
db
,
nil
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment