mirror of
https://github.com/miniflux/v2.git
synced 2025-07-22 17:18:37 +00:00
First commit
This commit is contained in:
commit
8ffb773f43
2121 changed files with 1118910 additions and 0 deletions
51
model/category.go
Normal file
51
model/category.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Category struct {
|
||||
ID int64 `json:"id,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
UserID int64 `json:"user_id,omitempty"`
|
||||
FeedCount int `json:"nb_feeds,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Category) String() string {
|
||||
return fmt.Sprintf("ID=%d, UserID=%d, Title=%s", c.ID, c.UserID, c.Title)
|
||||
}
|
||||
|
||||
func (c Category) ValidateCategoryCreation() error {
|
||||
if c.Title == "" {
|
||||
return errors.New("The title is mandatory")
|
||||
}
|
||||
|
||||
if c.UserID == 0 {
|
||||
return errors.New("The userID is mandatory")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Category) ValidateCategoryModification() error {
|
||||
if c.Title == "" {
|
||||
return errors.New("The title is mandatory")
|
||||
}
|
||||
|
||||
if c.UserID == 0 {
|
||||
return errors.New("The userID is mandatory")
|
||||
}
|
||||
|
||||
if c.ID == 0 {
|
||||
return errors.New("The ID is mandatory")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Categories []*Category
|
18
model/enclosure.go
Normal file
18
model/enclosure.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package model
|
||||
|
||||
// Enclosure represents an attachment.
|
||||
type Enclosure struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
EntryID int64 `json:"entry_id"`
|
||||
URL string `json:"url"`
|
||||
MimeType string `json:"mime_type"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
// EnclosureList represents a list of attachments.
|
||||
type EnclosureList []*Enclosure
|
71
model/entry.go
Normal file
71
model/entry.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
EntryStatusUnread = "unread"
|
||||
EntryStatusRead = "read"
|
||||
EntryStatusRemoved = "removed"
|
||||
DefaultSortingOrder = "published_at"
|
||||
DefaultSortingDirection = "desc"
|
||||
)
|
||||
|
||||
type Entry struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
FeedID int64 `json:"feed_id"`
|
||||
Status string `json:"status"`
|
||||
Hash string `json:"hash"`
|
||||
Title string `json:"title"`
|
||||
URL string `json:"url"`
|
||||
Date time.Time `json:"published_at"`
|
||||
Content string `json:"content"`
|
||||
Author string `json:"author"`
|
||||
Enclosures EnclosureList `json:"enclosures,omitempty"`
|
||||
Feed *Feed `json:"feed,omitempty"`
|
||||
Category *Category `json:"category,omitempty"`
|
||||
}
|
||||
|
||||
type Entries []*Entry
|
||||
|
||||
func ValidateEntryStatus(status string) error {
|
||||
switch status {
|
||||
case EntryStatusRead, EntryStatusUnread, EntryStatusRemoved:
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf(`Invalid entry status, valid status values are: "%s", "%s" and "%s"`, EntryStatusRead, EntryStatusUnread, EntryStatusRemoved)
|
||||
}
|
||||
|
||||
func ValidateEntryOrder(order string) error {
|
||||
switch order {
|
||||
case "id", "status", "published_at", "category_title", "category_id":
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf(`Invalid entry order, valid order values are: "id", "status", "published_at", "category_title", "category_id"`)
|
||||
}
|
||||
|
||||
func ValidateDirection(direction string) error {
|
||||
switch direction {
|
||||
case "asc", "desc":
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf(`Invalid direction, valid direction values are: "asc" or "desc"`)
|
||||
}
|
||||
|
||||
func GetOppositeDirection(direction string) string {
|
||||
if direction == "asc" {
|
||||
return "desc"
|
||||
}
|
||||
|
||||
return "asc"
|
||||
}
|
66
model/feed.go
Normal file
66
model/feed.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Feed represents a feed in the database
|
||||
type Feed struct {
|
||||
ID int64 `json:"id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
FeedURL string `json:"feed_url"`
|
||||
SiteURL string `json:"site_url"`
|
||||
Title string `json:"title"`
|
||||
CheckedAt time.Time `json:"checked_at,omitempty"`
|
||||
EtagHeader string `json:"etag_header,omitempty"`
|
||||
LastModifiedHeader string `json:"last_modified_header,omitempty"`
|
||||
ParsingErrorMsg string `json:"parsing_error_message,omitempty"`
|
||||
ParsingErrorCount int `json:"parsing_error_count,omitempty"`
|
||||
Category *Category `json:"category,omitempty"`
|
||||
Entries Entries `json:"entries,omitempty"`
|
||||
Icon *FeedIcon `json:"icon,omitempty"`
|
||||
}
|
||||
|
||||
func (f *Feed) String() string {
|
||||
return fmt.Sprintf("ID=%d, UserID=%d, FeedURL=%s, SiteURL=%s, Title=%s, Category={%s}",
|
||||
f.ID,
|
||||
f.UserID,
|
||||
f.FeedURL,
|
||||
f.SiteURL,
|
||||
f.Title,
|
||||
f.Category,
|
||||
)
|
||||
}
|
||||
|
||||
// Merge combine src to the current struct
|
||||
func (f *Feed) Merge(src *Feed) {
|
||||
src.ID = f.ID
|
||||
src.UserID = f.UserID
|
||||
|
||||
new := reflect.ValueOf(src).Elem()
|
||||
for i := 0; i < new.NumField(); i++ {
|
||||
field := new.Field(i)
|
||||
|
||||
switch field.Interface().(type) {
|
||||
case int64:
|
||||
value := field.Int()
|
||||
if value != 0 {
|
||||
reflect.ValueOf(f).Elem().Field(i).SetInt(value)
|
||||
}
|
||||
case string:
|
||||
value := field.String()
|
||||
if value != "" {
|
||||
reflect.ValueOf(f).Elem().Field(i).SetString(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Feeds is a list of feed
|
||||
type Feeds []*Feed
|
19
model/icon.go
Normal file
19
model/icon.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package model
|
||||
|
||||
// Icon represents a website icon (favicon)
|
||||
type Icon struct {
|
||||
ID int64 `json:"id"`
|
||||
Hash string `json:"hash"`
|
||||
MimeType string `json:"mime_type"`
|
||||
Content []byte `json:"content"`
|
||||
}
|
||||
|
||||
// FeedIcon is a jonction table between feeds and icons
|
||||
type FeedIcon struct {
|
||||
FeedID int64 `json:"feed_id"`
|
||||
IconID int64 `json:"icon_id"`
|
||||
}
|
10
model/job.go
Normal file
10
model/job.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package model
|
||||
|
||||
type Job struct {
|
||||
UserID int64
|
||||
FeedID int64
|
||||
}
|
23
model/session.go
Normal file
23
model/session.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package model
|
||||
|
||||
import "time"
|
||||
import "fmt"
|
||||
|
||||
type Session struct {
|
||||
ID int64
|
||||
UserID int64
|
||||
Token string
|
||||
CreatedAt time.Time
|
||||
UserAgent string
|
||||
IP string
|
||||
}
|
||||
|
||||
func (s *Session) String() string {
|
||||
return fmt.Sprintf("ID=%d, UserID=%d, IP=%s", s.ID, s.UserID, s.IP)
|
||||
}
|
||||
|
||||
type Sessions []*Session
|
13
model/theme.go
Normal file
13
model/theme.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package model
|
||||
|
||||
// GetThemes returns the list of available themes.
|
||||
func GetThemes() map[string]string {
|
||||
return map[string]string{
|
||||
"default": "Default",
|
||||
"black": "Black",
|
||||
}
|
||||
}
|
96
model/user.go
Normal file
96
model/user.go
Normal file
|
@ -0,0 +1,96 @@
|
|||
// Copyright 2017 Frédéric Guillot. All rights reserved.
|
||||
// Use of this source code is governed by the Apache 2.0
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// User represents a user in the system.
|
||||
type User struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password,omitempty"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
Theme string `json:"theme"`
|
||||
Language string `json:"language"`
|
||||
Timezone string `json:"timezone"`
|
||||
LastLoginAt *time.Time `json:"last_login_at"`
|
||||
}
|
||||
|
||||
func (u User) ValidateUserCreation() error {
|
||||
if err := u.ValidateUserLogin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := u.ValidatePassword(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u User) ValidateUserModification() error {
|
||||
if u.Username == "" {
|
||||
return errors.New("The username is mandatory")
|
||||
}
|
||||
|
||||
if err := u.ValidatePassword(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u User) ValidateUserLogin() error {
|
||||
if u.Username == "" {
|
||||
return errors.New("The username is mandatory")
|
||||
}
|
||||
|
||||
if u.Password == "" {
|
||||
return errors.New("The password is mandatory")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u User) ValidatePassword() error {
|
||||
if u.Password != "" && len(u.Password) < 6 {
|
||||
return errors.New("The password must have at least 6 characters")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Merge update the current user with another user.
|
||||
func (u *User) Merge(override *User) {
|
||||
if u.Username != override.Username {
|
||||
u.Username = override.Username
|
||||
}
|
||||
|
||||
if u.Password != override.Password {
|
||||
u.Password = override.Password
|
||||
}
|
||||
|
||||
if u.IsAdmin != override.IsAdmin {
|
||||
u.IsAdmin = override.IsAdmin
|
||||
}
|
||||
|
||||
if u.Theme != override.Theme {
|
||||
u.Theme = override.Theme
|
||||
}
|
||||
|
||||
if u.Language != override.Language {
|
||||
u.Language = override.Language
|
||||
}
|
||||
|
||||
if u.Timezone != override.Timezone {
|
||||
u.Timezone = override.Timezone
|
||||
}
|
||||
}
|
||||
|
||||
// Users represents a list of users.
|
||||
type Users []*User
|
Loading…
Add table
Add a link
Reference in a new issue