Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upload #67

Merged
merged 18 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ A personal documents server, Coreander indexes the documents (EPUBs and PDFs wit
* [Send to email supported](#send-to-email).
* Read indexed epubs and PDFs from Coreander's interface thanks to [epub.js](http://futurepress.org/) and [pdf.js](https://mozilla.github.io/pdf.js/).
* Restrictable access only to registered users.
* Upload documents through the web interface.

## Installation

Expand Down Expand Up @@ -79,7 +80,7 @@ Coreander can send documents through email. This way, you can take advantage of

### User management and access restriction

Coreander distinguish between two kinds of users: regular users and administrator users, with the latter being the only ones with the ability to create new users and delete documents.
Coreander distinguish between two kinds of users: regular users and administrator users, with the latter being the only ones with the ability to create new users and upload and delete documents.

By default, Coreander allow unrestricted access to its contents, except management areas which require an administrator user. To allow access only to registered users in the whole application, pass the `REQUIRE_AUTH=true` environment variable.

Expand All @@ -106,3 +107,5 @@ On first run, Coreander creates an admin user with the following credentials:
* `MIN_PASSWORD_LENGTH`: Minimum length acceptable for passwords. Defaults to 5.
* `WORDS_PER_MINUTE`: Defines a default words per minute reading speed that will be used for not logged-in users. Defaults to 250.
* `SESSION_TIMEOUT`: Specifies the maximum time a user session may last, in hours. Floating-point values are allowed. Defaults to 24 hours.
* `UPLOAD_DOCUMENT_MAX_SIZE`: Maximum document size allowed to be uploaded to the library, in megabytes. Set this to 0 to unlimit upload size. Defaults to 20 megabytes.

3 changes: 3 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ type Config struct {
WordsPerMinute float64 `env:"WORDS_PER_MINUTE" env-default:"250"`
// SessionTimeout specifies the maximum time a user session may last in hours
SessionTimeout float64 `env:"SESSION_TIMEOUT" env-default:"24"`
// UploadDocumentMaxSize is the maximum document size allowed to be uploaded to the library, in megabytes.
// Set this to 0 to unlimit upload size. Defaults to 20 megabytes.
UploadDocumentMaxSize int `env:"UPLOAD_DOCUMENT_MAX_SIZE" env-default:"20"`
}
2 changes: 1 addition & 1 deletion internal/index/bleve_write.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
func (b *BleveIndexer) AddFile(file string) error {
ext := strings.ToLower(filepath.Ext(file))
if _, ok := b.reader[ext]; !ok {
return nil
return fmt.Errorf("file extension %s not supported", ext)
}
meta, err := b.reader[ext].Metadata(file)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/metadata/epub.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func words(documentFullPath string) (int, error) {
defer r.Close()
count := 0
for _, f := range r.File {
isContent, err := doublestar.PathMatch("O*PS/**/*.*html", f.Name)
isContent, err := doublestar.PathMatch("O*PS/**/*.*htm*", f.Name)
if err != nil {
return 0, err
}
Expand Down
20 changes: 15 additions & 5 deletions internal/webserver/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@ func SetupControllers(cfg Config, db *gorm.DB, metadataReaders map[string]metada
}

documentsCfg := document.Config{
WordsPerMinute: cfg.WordsPerMinute,
LibraryPath: cfg.LibraryPath,
HomeDir: cfg.HomeDir,
CoverMaxWidth: cfg.CoverMaxWidth,
WordsPerMinute: cfg.WordsPerMinute,
LibraryPath: cfg.LibraryPath,
HomeDir: cfg.HomeDir,
CoverMaxWidth: cfg.CoverMaxWidth,
Hostname: cfg.Hostname,
Port: cfg.Port,
UploadDocumentMaxSize: cfg.UploadDocumentMaxSize,
}

authController := auth.NewController(usersRepository, sender, authCfg, printers)
Expand Down Expand Up @@ -97,6 +100,10 @@ func SetupControllers(cfg Config, db *gorm.DB, metadataReaders map[string]metada
SigningKey: cfg.JwtSecret,
SigningMethod: "HS256",
TokenLookup: "cookie:coreander",
SuccessHandler: func(c *fiber.Ctx) error {
c.Locals("Session", jwtclaimsreader.SessionData(c))
return c.Next()
},
ErrorHandler: func(c *fiber.Ctx, err error) error {
return forbidden(c)
},
Expand All @@ -105,6 +112,10 @@ func SetupControllers(cfg Config, db *gorm.DB, metadataReaders map[string]metada
SigningKey: cfg.JwtSecret,
SigningMethod: "HS256",
TokenLookup: "cookie:coreander",
SuccessHandler: func(c *fiber.Ctx) error {
c.Locals("Session", jwtclaimsreader.SessionData(c))
return c.Next()
},
ErrorHandler: func(c *fiber.Ctx, err error) error {
err = c.Next()
if cfg.RequireAuth {
Expand All @@ -116,7 +127,6 @@ func SetupControllers(cfg Config, db *gorm.DB, metadataReaders map[string]metada
ErrorHandler: func(c *fiber.Ctx, err error) error {
// Status code defaults to 500
code := fiber.StatusInternalServerError

// Retrieve the custom status code if it's a *fiber.Error
var e *fiber.Error
if errors.As(err, &e) {
Expand Down
16 changes: 0 additions & 16 deletions internal/webserver/controller/auth/controller.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package auth

import (
"fmt"
"time"

"github.com/gofiber/fiber/v2"
"github.com/svera/coreander/v3/internal/webserver/model"
"golang.org/x/text/message"
)
Expand Down Expand Up @@ -34,11 +32,6 @@ type Config struct {
SessionTimeout time.Duration
}

const (
defaultHttpPort = 80
defaultHttpsPort = 443
)

func NewController(repository authRepository, sender recoveryEmail, cfg Config, printers map[string]*message.Printer) *Controller {
return &Controller{
repository: repository,
Expand All @@ -47,12 +40,3 @@ func NewController(repository authRepository, sender recoveryEmail, cfg Config,
config: cfg,
}
}

func (a *Controller) urlPort(c *fiber.Ctx) string {
port := fmt.Sprintf(":%d", a.config.Port)
if (a.config.Port == defaultHttpPort && c.Protocol() == "http") ||
(a.config.Port == defaultHttpsPort && c.Protocol() == "https") {
port = ""
}
return port
}
3 changes: 2 additions & 1 deletion internal/webserver/controller/auth/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"strings"

"github.com/gofiber/fiber/v2"
"github.com/svera/coreander/v3/internal/webserver/controller"
"github.com/svera/coreander/v3/internal/webserver/infrastructure"
)

Expand All @@ -13,7 +14,7 @@ func (a *Controller) Login(c *fiber.Ctx) error {
"%s://%s%s/%s/reset-password",
c.Protocol(),
a.config.Hostname,
a.urlPort(c),
controller.UrlPort(c.Protocol(), a.config.Port),
c.Params("lang"),
)

Expand Down
3 changes: 2 additions & 1 deletion internal/webserver/controller/auth/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"github.com/svera/coreander/v3/internal/webserver/controller"
"github.com/svera/coreander/v3/internal/webserver/infrastructure"
)

Expand All @@ -33,7 +34,7 @@ func (a *Controller) Request(c *fiber.Ctx) error {
"%s://%s%s/%s/reset-password?id=%s",
c.Protocol(),
a.config.Hostname,
a.urlPort(c),
controller.UrlPort(c.Protocol(), a.config.Port),
c.Params("lang"),
user.RecoveryUUID,
)
Expand Down
17 changes: 17 additions & 0 deletions internal/webserver/controller/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package controller

import "fmt"

const (
defaultHttpPort = 80
defaultHttpsPort = 443
)

func UrlPort(protocol string, port int) string {
urlPort := fmt.Sprintf(":%d", port)
if (port == defaultHttpPort && protocol == "http") ||
(port == defaultHttpsPort && protocol == "https") {
urlPort = ""
}
return urlPort
}
12 changes: 8 additions & 4 deletions internal/webserver/controller/document/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type IdxReaderWriter interface {
SameSubjects(slug string, quantity int) ([]index.Document, error)
SameAuthors(slug string, quantity int) ([]index.Document, error)
SameSeries(slug string, quantity int) ([]index.Document, error)
AddFile(file string) error
RemoveFile(file string) error
Documents(IDs []string) (map[string]index.Document, error)
}
Expand All @@ -34,10 +35,13 @@ type highlightsRepository interface {
}

type Config struct {
WordsPerMinute float64
LibraryPath string
HomeDir string
CoverMaxWidth int
WordsPerMinute float64
LibraryPath string
HomeDir string
CoverMaxWidth int
Hostname string
Port int
UploadDocumentMaxSize int
}

type Controller struct {
Expand Down
9 changes: 6 additions & 3 deletions internal/webserver/controller/document/detail.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

"github.com/gofiber/fiber/v2"
"github.com/svera/coreander/v3/internal/webserver/infrastructure"
"github.com/svera/coreander/v3/internal/webserver/jwtclaimsreader"
"github.com/svera/coreander/v3/internal/webserver/model"
)

func (d *Controller) Detail(c *fiber.Ctx) error {
Expand All @@ -17,7 +17,11 @@ func (d *Controller) Detail(c *fiber.Ctx) error {
emailSendingConfigured = false
}

session := jwtclaimsreader.SessionData(c)
var session model.User
if val, ok := c.Locals("Session").(model.User); ok {
session = val
}

if session.WordsPerMinute > 0 {
d.config.WordsPerMinute = session.WordsPerMinute
}
Expand Down Expand Up @@ -61,7 +65,6 @@ func (d *Controller) Detail(c *fiber.Ctx) error {
"Document": document,
"EmailSendingConfigured": emailSendingConfigured,
"EmailFrom": d.sender.From(),
"Session": session,
"SameSeries": sameSeries,
"SameAuthors": sameAuthors,
"SameSubjects": sameSubjects,
Expand Down
9 changes: 5 additions & 4 deletions internal/webserver/controller/document/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/svera/coreander/v3/internal/index"
"github.com/svera/coreander/v3/internal/result"
"github.com/svera/coreander/v3/internal/webserver/infrastructure"
"github.com/svera/coreander/v3/internal/webserver/jwtclaimsreader"
"github.com/svera/coreander/v3/internal/webserver/model"
"github.com/svera/coreander/v3/internal/webserver/view"
)
Expand All @@ -23,7 +22,11 @@ func (d *Controller) Search(c *fiber.Ctx) error {
page = 1
}

session := jwtclaimsreader.SessionData(c)
var session model.User
if val, ok := c.Locals("Session").(model.User); ok {
session = val
}

if session.WordsPerMinute > 0 {
d.config.WordsPerMinute = session.WordsPerMinute
}
Expand All @@ -46,7 +49,6 @@ func (d *Controller) Search(c *fiber.Ctx) error {
"Title": "Search results",
"EmailSendingConfigured": emailSendingConfigured,
"EmailFrom": d.sender.From(),
"Session": session,
"WordsPerMinute": d.config.WordsPerMinute,
}, "layout")
}
Expand Down Expand Up @@ -77,7 +79,6 @@ func (d *Controller) Search(c *fiber.Ctx) error {
return c.Render("index", fiber.Map{
"Count": count,
"Title": "Coreander",
"Session": session,
"Highlights": docsSortedByHighlightedDate,
"EmailSendingConfigured": emailSendingConfigured,
"EmailFrom": d.sender.From(),
Expand Down
Loading
Loading