1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-07-22 17:18:37 +00:00

First commit

This commit is contained in:
Frédéric Guillot 2017-11-19 21:10:04 -08:00
commit 8ffb773f43
2121 changed files with 1118910 additions and 0 deletions

51
model/category.go Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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