initial commit
This commit is contained in:
commit
c21f569144
37 changed files with 3956 additions and 0 deletions
69
routes/auth.go
Normal file
69
routes/auth.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"foobar/database"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/joho/godotenv" // Carrega .env
|
||||
)
|
||||
|
||||
var store *sessions.CookieStore
|
||||
|
||||
const sessionIdCookie = "session_id"
|
||||
|
||||
func init() {
|
||||
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
key := os.Getenv("SESSION_STORE_KEY")
|
||||
|
||||
if key == "" {
|
||||
panic(fmt.Errorf("chave da sessão de cookies não foi definida."))
|
||||
}
|
||||
|
||||
store = sessions.NewCookieStore([]byte(key))
|
||||
}
|
||||
|
||||
func currentUser(r *http.Request) (*database.Usuario, error) {
|
||||
session, err := store.Get(r, sessionIdCookie)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, ok := session.Values["userId"].(int)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not ok")
|
||||
}
|
||||
|
||||
tx := database.MustBeginTx()
|
||||
defer tx.Rollback()
|
||||
|
||||
usuario, err := database.FindUsuarioByID(tx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return usuario, nil
|
||||
}
|
||||
|
||||
func redirectUnauthorized(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := store.Get(r, sessionIdCookie)
|
||||
if err != nil {
|
||||
logInternalError(w, err)
|
||||
return
|
||||
}
|
||||
session.AddFlash("Autenticação necessária.")
|
||||
err = session.Save(r, w)
|
||||
if err != nil {
|
||||
logInternalError(w, err)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/index.html", http.StatusFound)
|
||||
}
|
||||
69
routes/box.go
Normal file
69
routes/box.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"foobar/database"
|
||||
"foobar/model"
|
||||
"foobar/views"
|
||||
"net/http"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/gomarkdown/markdown/html"
|
||||
"github.com/gomarkdown/markdown/parser"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
)
|
||||
|
||||
func boxUpload(w http.ResponseWriter, r *http.Request) (templ.Component, error) {
|
||||
boxURL, err := GetBoxURL(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
box, err := database.SelectBox(boxURL)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return views.NewBox(boxURL, readmeTemplate), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return views.BoxUpload(box), nil
|
||||
}
|
||||
|
||||
func checkBox(w http.ResponseWriter, r *http.Request) (templ.Component, error) {
|
||||
boxURL, err := GetBoxURL(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
box, err := database.SelectBox(boxURL)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return views.Box(boxURL, []model.File{}), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
boxFiles, err := database.SelectBoxFiles(box.ID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return views.Box(boxURL, boxFiles), nil
|
||||
}
|
||||
|
||||
func mdToHTML(md []byte) model.Markdown {
|
||||
// create markdown parser with extensions
|
||||
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
|
||||
p := parser.NewWithExtensions(extensions)
|
||||
doc := p.Parse(md)
|
||||
|
||||
// create HTML renderer with extensions
|
||||
htmlFlags := html.CommonFlags | html.HrefTargetBlank
|
||||
opts := html.RendererOptions{Flags: htmlFlags}
|
||||
renderer := html.NewRenderer(opts)
|
||||
|
||||
sanitizer := bluemonday.UGCPolicy()
|
||||
return model.Markdown(sanitizer.SanitizeBytes(markdown.Render(doc, renderer)))
|
||||
}
|
||||
204
routes/file.go
Normal file
204
routes/file.go
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"foobar/database"
|
||||
"foobar/model"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var maxFileSize int64 = 32 * 1000 * 1000
|
||||
|
||||
func fileUpload(w http.ResponseWriter, r *http.Request) (redirectURL, error) {
|
||||
|
||||
boxURL, err := GetBoxURL(r)
|
||||
if err != nil {
|
||||
return noRedirect, err
|
||||
}
|
||||
|
||||
tx := database.MustBeginTx()
|
||||
defer tx.Rollback()
|
||||
|
||||
box, err := database.SelectBox(boxURL)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) { // this is a new URL the user wants to claim for themselves
|
||||
editCode := r.FormValue("edit_code")
|
||||
if editCode == "" {
|
||||
return noRedirect, newUserError(
|
||||
"Missing edit code. Box can't be created without it",
|
||||
)
|
||||
}
|
||||
var (
|
||||
id = uuid.New()
|
||||
createdAt = time.Now()
|
||||
lastUpdatedAt = createdAt
|
||||
header = readmeTemplate
|
||||
)
|
||||
newBox := model.NewBox(
|
||||
id, boxURL, editCode, header, false, false, createdAt, lastUpdatedAt,
|
||||
)
|
||||
err = database.InsertBox(tx, newBox, editCode, header)
|
||||
if err != nil {
|
||||
return noRedirect, err
|
||||
}
|
||||
box = newBox
|
||||
} else {
|
||||
return noRedirect, err
|
||||
}
|
||||
}
|
||||
|
||||
filesCtx, err := GetFilesFromUploadRequest(r)
|
||||
if err != nil {
|
||||
return noRedirect, err
|
||||
}
|
||||
|
||||
var files []model.File
|
||||
|
||||
for _, file := range filesCtx {
|
||||
|
||||
bytes, err := readFileBytes(file.FileHeader())
|
||||
if err != nil {
|
||||
return noRedirect, err
|
||||
}
|
||||
|
||||
mime := model.FileMime(http.DetectContentType(bytes))
|
||||
|
||||
if file.Filename() == "README.md" {
|
||||
|
||||
editCode := r.FormValue("edit_code")
|
||||
if editCode == "" {
|
||||
return noRedirect, newUserError(
|
||||
"Missing edit code. README can't be updated. " +
|
||||
"If you're not attempting to update the header, we'd " +
|
||||
"suggest changing \"README.md\" to a new filename.",
|
||||
)
|
||||
}
|
||||
|
||||
if editCode != box.EditCode() {
|
||||
return noRedirect, newUserError(
|
||||
"Wrong edit code.",
|
||||
)
|
||||
}
|
||||
|
||||
md := mdToHTML(bytes)
|
||||
|
||||
err := database.UpdateHeader(tx, box.ID(), md)
|
||||
if err != nil {
|
||||
return noRedirect, err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return noRedirect, err
|
||||
}
|
||||
|
||||
// FIXME: we're ignoring all other uploaded files
|
||||
return redirectURL(fmt.Sprintf("/box/%s", box.Url())), nil
|
||||
|
||||
} else {
|
||||
|
||||
err = copyBytesToDisk(file.ID(), bytes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
checksum := calculateMD5(bytes)
|
||||
|
||||
newFile := model.NewFile(
|
||||
file.ID(), file.Filename(), file.Size(),
|
||||
file.UploadedDate(), mime, checksum,
|
||||
)
|
||||
|
||||
files = append(files, newFile)
|
||||
}
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
err = database.InsertFile(tx, box.ID(), file)
|
||||
if err != nil {
|
||||
return noRedirect, err
|
||||
}
|
||||
}
|
||||
|
||||
if err = tx.Commit(); err != nil {
|
||||
return noRedirect, err
|
||||
}
|
||||
|
||||
return redirectURL(fmt.Sprintf("/box/%s/inside", box.Url())), nil
|
||||
}
|
||||
|
||||
func calculateMD5(fileBytes []byte) model.MD5Checksum {
|
||||
return md5.Sum(fileBytes)
|
||||
}
|
||||
|
||||
func readFileBytes(fileHeader *multipart.FileHeader) ([]byte, error) {
|
||||
fileReader, err := fileHeader.Open()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fileReader.Close()
|
||||
|
||||
fileBytes, err := io.ReadAll(fileReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fileBytes, nil
|
||||
}
|
||||
|
||||
func copyBytesToDisk(fileId uuid.UUID, fileBytes []byte) error {
|
||||
fileWriter, err := os.Create(filepath.Join(
|
||||
staticDir, "box", fmt.Sprintf(fileId.String())),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fileWriter.Close()
|
||||
|
||||
_, err = io.Copy(fileWriter, bytes.NewReader(fileBytes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetFilesFromUploadRequest(r *http.Request) ([]model.FileUploadContext, error) {
|
||||
|
||||
err := r.ParseMultipartForm(int64(maxFileSize))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
headers, ok := r.MultipartForm.File["file"]
|
||||
if !ok {
|
||||
return nil, newUserError("no file")
|
||||
}
|
||||
|
||||
var (
|
||||
files []model.FileUploadContext
|
||||
)
|
||||
|
||||
for _, header := range headers {
|
||||
var (
|
||||
id = uuid.New()
|
||||
uploadedDate = time.Now()
|
||||
size = header.Size
|
||||
filename = model.Filename(header.Filename)
|
||||
mime = model.MimeFromHeader(header.Header)
|
||||
)
|
||||
|
||||
fileUpload := model.NewFileUploadContext(id, uploadedDate, size, filename, mime, header)
|
||||
files = append(files, fileUpload)
|
||||
}
|
||||
return files, nil
|
||||
|
||||
}
|
||||
97
routes/logging.go
Normal file
97
routes/logging.go
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"foobar/metrics"
|
||||
"log"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
type wrappedWriter struct {
|
||||
http.ResponseWriter
|
||||
statusCode int
|
||||
}
|
||||
|
||||
func (w *wrappedWriter) WriteHeader(statusCode int) {
|
||||
w.ResponseWriter.WriteHeader(statusCode)
|
||||
w.statusCode = statusCode
|
||||
}
|
||||
|
||||
func logging(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
|
||||
wrapped := &wrappedWriter{
|
||||
ResponseWriter: w,
|
||||
statusCode: http.StatusOK,
|
||||
}
|
||||
|
||||
var panicked bool
|
||||
err := recoverServeHTTP(next, wrapped, r)
|
||||
if err != nil {
|
||||
wrapped.Write([]byte("500 error"))
|
||||
log.Println(err)
|
||||
panicked = true
|
||||
}
|
||||
|
||||
var (
|
||||
latency = time.Since(start)
|
||||
path = r.URL.Path
|
||||
statusCode = wrapped.statusCode
|
||||
)
|
||||
if path == "/metrics" && statusCode == 200 {
|
||||
return
|
||||
}
|
||||
log.Printf("%v %v %v %v", wrapped.statusCode, r.Method, r.URL.Path, latency)
|
||||
|
||||
metrics.ResponseLatencyObserve(latency, statusCode, panicked, r)
|
||||
})
|
||||
}
|
||||
|
||||
func recoverServeHTTP(next http.Handler, w http.ResponseWriter, r *http.Request) (e error) {
|
||||
defer func() {
|
||||
if rec := recover(); rec != nil {
|
||||
var err error
|
||||
switch v := rec.(type) {
|
||||
case error:
|
||||
err = v
|
||||
default:
|
||||
err = fmt.Errorf("%v", v)
|
||||
}
|
||||
stack := debug.Stack()
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
e = errors.Join(err, fmt.Errorf(string(stack)))
|
||||
}
|
||||
}()
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
func logError(err error) {
|
||||
if err == nil {
|
||||
log.Printf("LOG: Erro Nulo!?\n")
|
||||
} else {
|
||||
log.Printf("LOG: %s\n", err.Error())
|
||||
}
|
||||
log.Println(string(debug.Stack()))
|
||||
}
|
||||
|
||||
func logInternalError(w http.ResponseWriter, err error) {
|
||||
logError(err)
|
||||
http.Error(w, `500`, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func httpErrorf(w http.ResponseWriter, status int, formatString string, format ...interface{}) {
|
||||
http.Error(w, fmt.Sprintf(formatString, format...), status)
|
||||
}
|
||||
|
||||
func formValueMissing(field string, r *http.Request) error {
|
||||
return fmt.Errorf(
|
||||
"campo '%s' em formulário não pôde ser encontrado. Content-Type: %s",
|
||||
field,
|
||||
r.Header.Get("Content-Type"),
|
||||
)
|
||||
}
|
||||
97
routes/middleware.go
Normal file
97
routes/middleware.go
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"foobar/views"
|
||||
"net/http"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
)
|
||||
|
||||
type userError struct {
|
||||
error
|
||||
user string
|
||||
}
|
||||
|
||||
type redirectURL string
|
||||
|
||||
type postRouteRedirectFunc func(http.ResponseWriter, *http.Request) (redirectURL, error)
|
||||
|
||||
type routeGetFunc func(http.ResponseWriter, *http.Request) (templ.Component, error)
|
||||
|
||||
var (
|
||||
errUser = errors.New("user error")
|
||||
)
|
||||
|
||||
func newUserError(msg string) *userError {
|
||||
return &userError{
|
||||
user: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *userError) Error() string {
|
||||
return u.user
|
||||
}
|
||||
|
||||
func (u redirectURL) Valid() bool {
|
||||
return len(u) > 0 && u[0] == '/'
|
||||
}
|
||||
|
||||
func getRouteMiddleware(fun routeGetFunc) http.HandlerFunc {
|
||||
// TODO: handle boosted HTMX requests gracefully
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
component, err := fun(w, r)
|
||||
if err != nil {
|
||||
logInternalError(w, err)
|
||||
return
|
||||
}
|
||||
err = component.Render(context.Background(), w)
|
||||
if err != nil {
|
||||
logInternalError(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func redirectHtmxFormMiddleware(fun postRouteRedirectFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
hxRequest := r.Header.Get("HX-Request") == "true"
|
||||
|
||||
redirectURL, err := fun(w, r)
|
||||
if err != nil {
|
||||
w.Header().Add("HX-Retarget", "#error-target")
|
||||
w.Header().Add("HX-Reswap", "innerHTML")
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
if u, ok := err.(*userError); ok {
|
||||
if hxRequest {
|
||||
err = views.ErrorBox(u.user).Render(context.Background(), w)
|
||||
if err != nil {
|
||||
logError(fmt.Errorf("%w: %s", err, r.URL.Path))
|
||||
}
|
||||
} else {
|
||||
_, _ = w.Write([]byte(u.user))
|
||||
|
||||
}
|
||||
return
|
||||
} else {
|
||||
msg := "Internal error... See the server logs for more information"
|
||||
_ = views.ErrorBox(msg).Render(context.Background(), w)
|
||||
logError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !redirectURL.Valid() {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
if hxRequest {
|
||||
w.Header().Add("HX-Redirect", string(redirectURL))
|
||||
} else {
|
||||
http.Redirect(w, r, string(redirectURL), http.StatusFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
178
routes/routes.go
Normal file
178
routes/routes.go
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"foobar/database"
|
||||
"foobar/model"
|
||||
"foobar/views"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
const noRedirect redirectURL = ""
|
||||
|
||||
var (
|
||||
mux *http.ServeMux = nil
|
||||
errBoxNotFound error = fmt.Errorf("box id not found")
|
||||
staticDir string = filepath.Join("views", "static")
|
||||
)
|
||||
|
||||
var readmeTemplate model.Markdown
|
||||
|
||||
func init() {
|
||||
mux = http.NewServeMux()
|
||||
if err := os.MkdirAll(staticDir, 777); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServerFS(os.DirFS(staticDir))))
|
||||
|
||||
mux.HandleFunc("/", index)
|
||||
mux.HandleFunc("POST /box/{box}", redirectHtmxFormMiddleware(fileUpload))
|
||||
mux.HandleFunc("GET /box/{box}", getRouteMiddleware(boxUpload))
|
||||
mux.HandleFunc("GET /box/{box}/inside", getRouteMiddleware(checkBox))
|
||||
|
||||
mux.HandleFunc("/panic", func(w http.ResponseWriter, r *http.Request) {
|
||||
panic("não implementado")
|
||||
})
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
var buf bytes.Buffer
|
||||
err := template.Must(template.ParseFiles(filepath.Join(staticDir, "default", "README.md"))).
|
||||
Execute(&buf, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
readmeTemplate = mdToHTML(buf.Bytes())
|
||||
}
|
||||
|
||||
func Mux() http.Handler {
|
||||
return logging(mux)
|
||||
}
|
||||
|
||||
func notFound(w http.ResponseWriter) {
|
||||
w.WriteHeader(404)
|
||||
if err := views.FourOfour().Render(context.Background(), w); err != nil {
|
||||
logInternalError(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func index(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/index.html" && r.URL.Path != "/" || r.Method != "GET" {
|
||||
notFound(w)
|
||||
return
|
||||
}
|
||||
if err := views.Index().Render(context.Background(), w); err != nil {
|
||||
logInternalError(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func GetBoxURL(r *http.Request) (model.BoxURL, error) {
|
||||
return model.CheckBoxURL(r.PathValue("box"))
|
||||
}
|
||||
|
||||
// func sobre(w http.ResponseWriter, r *http.Request) {
|
||||
// if err := views.Sobre().Render(context.Background(), w); err != nil {
|
||||
// logInternalError(w, err)
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
|
||||
// func logIn(w http.ResponseWriter, r *http.Request) {
|
||||
//
|
||||
// _, err := currentUser(r)
|
||||
//
|
||||
// userLogged := err == nil
|
||||
//
|
||||
// if userLogged {
|
||||
// http.Redirect(w, r, "/logged", http.StatusFound)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// if err := views.Login().Render(context.Background(), w); err != nil {
|
||||
// logInternalError(w, err)
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
|
||||
func logInPOST(w http.ResponseWriter, r *http.Request) (redirectURL, error) {
|
||||
|
||||
email := r.FormValue("email")
|
||||
if email == "" {
|
||||
return "", formValueMissing("email", r)
|
||||
}
|
||||
|
||||
senha := r.FormValue("senha")
|
||||
if senha == "" {
|
||||
return "", formValueMissing("senha", r)
|
||||
}
|
||||
|
||||
tx := database.MustBeginTx()
|
||||
defer tx.Rollback()
|
||||
|
||||
usuario, err := database.VerifyUser(tx, email, senha)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) || errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
|
||||
return "", newUserError("senha ou email não conferem")
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
session, err := store.Get(r, sessionIdCookie)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
userId, err := usuario.Id()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
session.Values["userId"] = userId
|
||||
session.Options.SameSite = http.SameSiteDefaultMode
|
||||
|
||||
if err := session.Save(r, w); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return "/logged", nil
|
||||
}
|
||||
|
||||
func logged(w http.ResponseWriter, r *http.Request) {
|
||||
usuario, err := currentUser(r)
|
||||
if err != nil {
|
||||
logError(err)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte("Não Autorizado."))
|
||||
return
|
||||
}
|
||||
if err = views.Logged(usuario).Render(context.Background(), w); err != nil {
|
||||
logInternalError(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func logout(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := store.Get(r, sessionIdCookie)
|
||||
if err != nil {
|
||||
logInternalError(w, err)
|
||||
return
|
||||
}
|
||||
session.Options.MaxAge = -1
|
||||
if err = session.Save(r, w); err != nil {
|
||||
logInternalError(w, err)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/login", http.StatusFound)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue