New structure (#7)

This commit is contained in:
konrad 2018-10-31 12:42:38 +00:00 committed by Gitea
parent 3f9fad0e2a
commit 301a4eedda
104 changed files with 326 additions and 280 deletions

20
main.go
View File

@ -1,9 +1,11 @@
package main
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/models/mail"
"code.vikunja.io/api/routes"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/mail"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/routes"
"context"
"github.com/spf13/viper"
@ -18,19 +20,19 @@ var Version = "0.1"
func main() {
// Init logging
models.InitLogger()
log.InitLogger()
// Init Config
err := models.InitConfig()
err := config.InitConfig()
if err != nil {
models.Log.Error(err.Error())
log.Log.Error(err.Error())
os.Exit(1)
}
// Set Engine
err = models.SetEngine()
if err != nil {
models.Log.Error(err.Error())
log.Log.Error(err.Error())
os.Exit(1)
}
@ -38,7 +40,7 @@ func main() {
mail.StartMailDaemon()
// Version notification
models.Log.Infof("Vikunja version %s", Version)
log.Log.Infof("Vikunja version %s", Version)
// Start the webserver
e := routes.NewEcho()
@ -57,7 +59,7 @@ func main() {
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
models.Log.Infof("Sutting down...")
log.Log.Infof("Shutting down...")
if err := e.Shutdown(ctx); err != nil {
e.Logger.Fatal(err)
}

View File

@ -1,80 +0,0 @@
package models
// TeamRight defines the rights teams can have for lists/namespaces
type TeamRight int
// define unknown team right
const (
TeamRightUnknown = -1
)
// Enumerate all the team rights
const (
// Can read lists in a Team
TeamRightRead TeamRight = iota
// Can write tasks in a Team like lists and todo tasks. Cannot create new lists.
TeamRightWrite
// Can manage a list/namespace, can do everything
TeamRightAdmin
)
func (r TeamRight) isValid() error {
if r != TeamRightAdmin && r != TeamRightRead && r != TeamRightWrite {
return ErrInvalidTeamRight{r}
}
return nil
}
// CanCreate checks if the user can create a new team
func (t *Team) CanCreate(user *User) bool {
// This is currently a dummy function, later on we could imagine global limits etc.
return true
}
// CanUpdate checks if the user can update a team
func (t *Team) CanUpdate(user *User) bool {
// Check if the current user is in the team and has admin rights in it
exists, err := x.Where("team_id = ?", t.ID).
And("user_id = ?", user.ID).
And("admin = ?", true).
Get(&TeamMember{})
if err != nil {
Log.Error("Error occurred during CanUpdate for Team: %s", err)
return false
}
return exists
}
// CanDelete checks if a user can delete a team
func (t *Team) CanDelete(user *User) bool {
return t.IsAdmin(user)
}
// IsAdmin returns true when the user is admin of a team
func (t *Team) IsAdmin(user *User) bool {
exists, err := x.Where("team_id = ?", t.ID).
And("user_id = ?", user.ID).
And("admin = ?", true).
Get(&TeamMember{})
if err != nil {
Log.Error("Error occurred during CanUpdate for Team: %s", err)
return false
}
return exists
}
// CanRead returns true if the user has read access to the team
func (t *Team) CanRead(user *User) bool {
// Check if the user is in the team
exists, err := x.Where("team_id = ?", t.ID).
And("user_id = ?", user.ID).
Get(&TeamMember{})
if err != nil {
Log.Error("Error occurred during CanUpdate for Team: %s", err)
return false
}
return exists
}

View File

@ -1,4 +1,4 @@
package models
package config
import (
"crypto/rand"

View File

@ -1,4 +1,4 @@
package models
package log
import (
"github.com/op/go-logging"

View File

@ -1,8 +1,8 @@
package mail
import (
"code.vikunja.io/api/pkg/log"
"crypto/tls"
"fmt"
"github.com/spf13/viper"
"gopkg.in/gomail.v2"
"time"
@ -16,8 +16,7 @@ func StartMailDaemon() {
Queue = make(chan *gomail.Message, viper.GetInt("mailer.queuelength"))
if viper.GetString("mailer.host") == "" {
//models.Log.Warning("Mailer seems to be not configured! Please see the config docs for more details.")
fmt.Println("Mailer seems to be not configured! Please see the config docs for more details.")
log.Log.Warning("Mailer seems to be not configured! Please see the config docs for more details.")
return
}
@ -36,23 +35,21 @@ func StartMailDaemon() {
}
if !open {
if s, err = d.Dial(); err != nil {
// models.Log.Error("Error during connect to smtp server: %s", err)
fmt.Printf("Error during connect to smtp server: %s \n", err)
log.Log.Error("Error during connect to smtp server: %s", err)
}
open = true
}
if err := gomail.Send(s, m); err != nil {
// models.Log.Error("Error when sending mail: %s", err)
fmt.Printf("Error when sending mail: %s \n", err)
log.Log.Error("Error when sending mail: %s", err)
}
// Close the connection to the SMTP server if no email was sent in
// the last 30 seconds.
case <-time.After(viper.GetDuration("mailer.queuetimeout") * time.Second):
if open {
if err := s.Close(); err != nil {
fmt.Printf("Error closing the mail server connection: %s\n", err)
log.Log.Error("Error closing the mail server connection: %s\n", err)
}
fmt.Println("Closed connection to mailserver")
log.Log.Infof("Closed connection to mailserver")
open = false
}
}

View File

@ -2,7 +2,7 @@ package mail
import (
"bytes"
"code.vikunja.io/api/models/utils"
"code.vikunja.io/api/pkg/utils"
"github.com/labstack/gommon/log"
"github.com/spf13/viper"
"gopkg.in/gomail.v2"

View File

@ -25,9 +25,9 @@ func GetListsByNamespaceID(nID int64) (lists []*List, err error) {
}
// ReadAll gets all lists a user has access to
func (l *List) ReadAll(user *User) (interface{}, error) {
func (l *List) ReadAll(u *User) (interface{}, error) {
lists := []*List{}
fullUser, err := GetUserByID(user.ID)
fullUser, err := GetUserByID(u.ID)
if err != nil {
return lists, err
}
@ -53,7 +53,7 @@ func (l *List) ReadAll(user *User) (interface{}, error) {
Find(&lists)
// Add more list details
addListDetails(lists)
AddListDetails(lists)
return lists, err
}
@ -98,8 +98,8 @@ func (l *List) GetSimpleByID() (err error) {
return
}
// Adds owner user objects and list tasks to all lists in the slice
func addListDetails(lists []*List) (err error) {
// AddListDetails adds owner user objects and list tasks to all lists in the slice
func AddListDetails(lists []*List) (err error) {
var listIDs []int64
var ownerIDs []int64
for _, l := range lists {
@ -108,8 +108,8 @@ func addListDetails(lists []*List) (err error) {
}
// Get all tasks
tasks := []*ListTask{}
err = x.In("list_id", listIDs).Find(&tasks)
ts := []*ListTask{}
err = x.In("list_id", listIDs).Find(&ts)
if err != nil {
return
}
@ -132,7 +132,7 @@ func addListDetails(lists []*List) (err error) {
}
// Tasks
for _, task := range tasks {
for _, task := range ts {
if task.ListID == list.ID {
lists[in].Tasks = append(lists[in].Tasks, task)
}

View File

@ -44,13 +44,13 @@ func (l *List) Update() (err error) {
// Create implements the create method of CRUDable
func (l *List) Create(doer *User) (err error) {
// Check rights
user, err := GetUserByID(doer.ID)
u, err := GetUserByID(doer.ID)
if err != nil {
return
}
l.OwnerID = user.ID
l.Owner.ID = user.ID
l.OwnerID = u.ID
l.Owner.ID = u.ID
l.ID = 0 // Otherwise only the first time a new list would be created
return CreateOrUpdateList(l)

View File

@ -16,11 +16,11 @@ func TestList_ReadAll(t *testing.T) {
assert.Equal(t, len(lists), 2)
// Get all lists our user has access to
user, err := GetUserByID(1)
u, err := GetUserByID(1)
assert.NoError(t, err)
lists2 := List{}
lists3, err := lists2.ReadAll(&user)
lists3, err := lists2.ReadAll(&u)
assert.NoError(t, err)
assert.Equal(t, reflect.TypeOf(lists3).Kind(), reflect.Slice)
s := reflect.ValueOf(lists3)

View File

@ -1,18 +1,22 @@
package models
import (
"code.vikunja.io/api/pkg/log"
)
// IsAdmin returns whether the user has admin rights on the list or not
func (l *List) IsAdmin(user *User) bool {
func (l *List) IsAdmin(u *User) bool {
// Owners are always admins
if l.Owner.ID == user.ID {
if l.Owner.ID == u.ID {
return true
}
// Check individual rights
if l.checkListUserRight(user, UserRightAdmin) {
if l.checkListUserRight(u, UserRightAdmin) {
return true
}
return l.checkListTeamRight(user, TeamRightAdmin)
return l.checkListTeamRight(u, TeamRightAdmin)
}
// CanWrite return whether the user can write on that list or not
@ -48,7 +52,7 @@ func (l *List) CanRead(user *User) bool {
// CanDelete checks if the user can delete a list
func (l *List) CanDelete(doer *User) bool {
if err := l.GetSimpleByID(); err != nil {
Log.Error("Error occurred during CanDelete for List: %s", err)
log.Log.Error("Error occurred during CanDelete for List: %s", err)
return false
}
return l.IsAdmin(doer)
@ -57,7 +61,7 @@ func (l *List) CanDelete(doer *User) bool {
// CanUpdate checks if the user can update a list
func (l *List) CanUpdate(doer *User) bool {
if err := l.GetSimpleByID(); err != nil {
Log.Error("Error occurred during CanUpdate for List: %s", err)
log.Log.Error("Error occurred during CanUpdate for List: %s", err)
return false
}
return l.CanWrite(doer)
@ -82,7 +86,7 @@ func (l *List) checkListTeamRight(user *User, r TeamRight) bool {
user.ID, r, user.ID, r, l.ID).
Exist(&List{})
if err != nil {
Log.Error("Error occurred during checkListTeamRight for List: %s", err)
log.Log.Error("Error occurred during checkListTeamRight for List: %s", err)
return false
}
@ -103,7 +107,7 @@ func (l *List) checkListUserRight(user *User, r UserRight) bool {
user.ID, r, user.ID, r, user.ID, l.ID).
Exist(&List{})
if err != nil {
Log.Error("Error occurred during checkListUserRight for List: %s", err)
log.Log.Error("Error occurred during checkListUserRight for List: %s", err)
return false
}

View File

@ -59,9 +59,9 @@ func GetTasksByListID(listID int64) (tasks []*ListTask, err error) {
}
for in, task := range tasks {
for _, user := range users {
if task.CreatedByID == user.ID {
tasks[in].CreatedBy = user
for _, u := range users {
if task.CreatedByID == u.ID {
tasks[in].CreatedBy = u
break
}
}
@ -88,11 +88,11 @@ func GetListTaskByID(listTaskID int64) (listTask ListTask, err error) {
return ListTask{}, ErrListTaskDoesNotExist{listTaskID}
}
user, err := GetUserByID(listTask.CreatedByID)
u, err := GetUserByID(listTask.CreatedByID)
if err != nil {
return
}
listTask.CreatedBy = user
listTask.CreatedBy = u
return
}

View File

@ -19,13 +19,13 @@ func (i *ListTask) Create(doer *User) (err error) {
return
}
user, err := GetUserByID(doer.ID)
u, err := GetUserByID(doer.ID)
if err != nil {
return err
}
i.CreatedByID = user.ID
i.CreatedBy = user
i.CreatedByID = u.ID
i.CreatedBy = u
_, err = x.Cols("text", "description", "done", "due_date_unix", "reminder_unix", "created_by_id", "list_id", "created", "updated").Insert(i)
return err
}
@ -39,8 +39,8 @@ func (i *ListTask) Update() (err error) {
}
// For whatever reason, xorm dont detect if done is updated, so we need to update this every time by hand
// Which is why we merge the actual task struct with the one we got from the user.
// The user struct ovverrides values in the actual one.
// Which is why we merge the actual task struct with the one we got from the
// The user struct overrides values in the actual one.
if err := mergo.Merge(&ot, i, mergo.WithOverride); err != nil {
return err
}

View File

@ -1,18 +1,22 @@
package models
import (
"code.vikunja.io/api/pkg/log"
)
// CanDelete checks if the user can delete an task
func (i *ListTask) CanDelete(doer *User) bool {
// Get the task
lI, err := GetListTaskByID(i.ID)
if err != nil {
Log.Error("Error occurred during CanDelete for ListTask: %s", err)
log.Log.Error("Error occurred during CanDelete for ListTask: %s", err)
return false
}
// A user can delete an task if he has write acces to its list
list := &List{ID: lI.ListID}
list.ReadOne()
return list.CanWrite(doer)
l := &List{ID: lI.ListID}
l.ReadOne()
return l.CanWrite(doer)
}
// CanUpdate determines if a user has the right to update a list task
@ -20,20 +24,20 @@ func (i *ListTask) CanUpdate(doer *User) bool {
// Get the task
lI, err := GetListTaskByID(i.ID)
if err != nil {
Log.Error("Error occurred during CanDelete for ListTask: %s", err)
log.Log.Error("Error occurred during CanDelete for ListTask: %s", err)
return false
}
// A user can update an task if he has write acces to its list
list := &List{ID: lI.ListID}
list.ReadOne()
return list.CanWrite(doer)
l := &List{ID: lI.ListID}
l.ReadOne()
return l.CanWrite(doer)
}
// CanCreate determines if a user has the right to create a list task
func (i *ListTask) CanCreate(doer *User) bool {
// A user can create an task if he has write acces to its list
list := &List{ID: i.ListID}
list.ReadOne()
return list.CanWrite(doer)
l := &List{ID: i.ListID}
l.ReadOne()
return l.CanWrite(doer)
}

View File

@ -1,7 +1,7 @@
package models
// Create creates a new list <-> user relation
func (ul *ListUser) Create(user *User) (err error) {
func (ul *ListUser) Create(u *User) (err error) {
// Check if the right is valid
if err := ul.Right.isValid(); err != nil {

View File

@ -1,13 +1,13 @@
package models
// ReadAll gets all users who have access to a list
func (ul *ListUser) ReadAll(user *User) (interface{}, error) {
func (ul *ListUser) ReadAll(u *User) (interface{}, error) {
// Check if the user has access to the list
l := &List{ID: ul.ListID}
if err := l.GetSimpleByID(); err != nil {
return nil, err
}
if !l.CanRead(user) {
if !l.CanRead(u) {
return nil, ErrNeedToHaveListReadAccess{}
}

View File

@ -1,37 +1,15 @@
package models
// UserRight defines the rights users can have for lists/namespaces
type UserRight int
// define unknown user right
const (
UserRightUnknown = -1
import (
"code.vikunja.io/api/pkg/log"
)
// Enumerate all the user rights
const (
// Can read lists in a User
UserRightRead UserRight = iota
// Can write tasks in a User like lists and todo tasks. Cannot create new lists.
UserRightWrite
// Can manage a list/namespace, can do everything
UserRightAdmin
)
func (r UserRight) isValid() error {
if r != UserRightAdmin && r != UserRightRead && r != UserRightWrite {
return ErrInvalidUserRight{r}
}
return nil
}
// CanCreate checks if the user can create a new user <-> list relation
func (lu *ListUser) CanCreate(doer *User) bool {
// Get the list and check if the user has write access on it
l := List{ID: lu.ListID}
if err := l.GetSimpleByID(); err != nil {
Log.Error("Error occurred during CanCreate for ListUser: %s", err)
log.Log.Error("Error occurred during CanCreate for ListUser: %s", err)
return false
}
return l.CanWrite(doer)
@ -42,7 +20,7 @@ func (lu *ListUser) CanDelete(doer *User) bool {
// Get the list and check if the user has write access on it
l := List{ID: lu.ListID}
if err := l.GetSimpleByID(); err != nil {
Log.Error("Error occurred during CanDelete for ListUser: %s", err)
log.Log.Error("Error occurred during CanDelete for ListUser: %s", err)
return false
}
return l.CanWrite(doer)
@ -53,7 +31,7 @@ func (lu *ListUser) CanUpdate(doer *User) bool {
// Get the list and check if the user has write access on it
l := List{ID: lu.ListID}
if err := l.GetSimpleByID(); err != nil {
Log.Error("Error occurred during CanUpdate for ListUser: %s", err)
log.Log.Error("Error occurred during CanUpdate for ListUser: %s", err)
return false
}
return l.CanWrite(doer)

View File

@ -109,7 +109,7 @@ func (n *Namespace) ReadAll(doer *User) (interface{}, error) {
}
// More details for the lists
addListDetails(lists)
AddListDetails(lists)
// Put objects in our namespace list
for i, n := range all {

View File

@ -21,8 +21,8 @@ func (n *Namespace) Delete() (err error) {
// We need to do that for here because we need the list ids to delete two times:
// 1) to delete the lists itself
// 2) to delete the list tasks
for _, list := range lists {
listIDs = append(listIDs, list.ID)
for _, l := range lists {
listIDs = append(listIDs, l.ID)
}
// Delete tasks

View File

@ -1,106 +1,110 @@
package models
import (
"code.vikunja.io/api/pkg/log"
)
// IsAdmin returns true or false if the user is admin on that namespace or not
func (n *Namespace) IsAdmin(user *User) bool {
func (n *Namespace) IsAdmin(u *User) bool {
// Owners always have admin rights
if user.ID == n.Owner.ID {
if u.ID == n.Owner.ID {
return true
}
// Check user rights
if n.checkUserRights(user, UserRightAdmin) {
if n.checkUserRights(u, UserRightAdmin) {
return true
}
// Check if that user is in a team which has admin rights to that namespace
return n.checkTeamRights(user, TeamRightAdmin)
return n.checkTeamRights(u, TeamRightAdmin)
}
// CanWrite checks if a user has write access to a namespace
func (n *Namespace) CanWrite(user *User) bool {
func (n *Namespace) CanWrite(u *User) bool {
// Admins always have write access
if n.IsAdmin(user) {
if n.IsAdmin(u) {
return true
}
// Check user rights
if n.checkUserRights(user, UserRightWrite) {
if n.checkUserRights(u, UserRightWrite) {
return true
}
// Check if that user is in a team which has write rights to that namespace
return n.checkTeamRights(user, TeamRightWrite)
return n.checkTeamRights(u, TeamRightWrite)
}
// CanRead checks if a user has read access to that namespace
func (n *Namespace) CanRead(user *User) bool {
func (n *Namespace) CanRead(u *User) bool {
// Admins always have read access
if n.IsAdmin(user) {
if n.IsAdmin(u) {
return true
}
// Check user rights
if n.checkUserRights(user, UserRightRead) {
if n.checkUserRights(u, UserRightRead) {
return true
}
// Check if the user is in a team which has access to the namespace
return n.checkTeamRights(user, TeamRightRead)
return n.checkTeamRights(u, TeamRightRead)
}
// CanUpdate checks if the user can update the namespace
func (n *Namespace) CanUpdate(user *User) bool {
func (n *Namespace) CanUpdate(u *User) bool {
nn, err := GetNamespaceByID(n.ID)
if err != nil {
Log.Error("Error occurred during CanUpdate for Namespace: %s", err)
log.Log.Error("Error occurred during CanUpdate for Namespace: %s", err)
return false
}
return nn.IsAdmin(user)
return nn.IsAdmin(u)
}
// CanDelete checks if the user can delete a namespace
func (n *Namespace) CanDelete(user *User) bool {
func (n *Namespace) CanDelete(u *User) bool {
nn, err := GetNamespaceByID(n.ID)
if err != nil {
Log.Error("Error occurred during CanDelete for Namespace: %s", err)
log.Log.Error("Error occurred during CanDelete for Namespace: %s", err)
return false
}
return nn.IsAdmin(user)
return nn.IsAdmin(u)
}
// CanCreate checks if the user can create a new namespace
func (n *Namespace) CanCreate(user *User) bool {
func (n *Namespace) CanCreate(u *User) bool {
// This is currently a dummy function, later on we could imagine global limits etc.
return true
}
func (n *Namespace) checkTeamRights(user *User, r TeamRight) bool {
func (n *Namespace) checkTeamRights(u *User, r TeamRight) bool {
exists, err := x.Select("namespaces.*").
Table("namespaces").
Join("LEFT", "team_namespaces", "namespaces.id = team_namespaces.namespace_id").
Join("LEFT", "team_members", "team_members.team_id = team_namespaces.team_id").
Where("namespaces.id = ? "+
"AND (team_members.user_id = ? AND team_namespaces.right = ?) "+
"OR namespaces.owner_id = ? ", n.ID, user.ID, r, user.ID).
"OR namespaces.owner_id = ? ", n.ID, u.ID, r, u.ID).
Get(&Namespace{})
if err != nil {
Log.Error("Error occurred during checkTeamRights for Namespace: %s, TeamRight: %d", err, r)
log.Log.Error("Error occurred during checkTeamRights for Namespace: %s, TeamRight: %d", err, r)
return false
}
return exists
}
func (n *Namespace) checkUserRights(user *User, r UserRight) bool {
func (n *Namespace) checkUserRights(u *User, r UserRight) bool {
exists, err := x.Select("namespaces.*").
Table("namespaces").
Join("LEFT", "users_namespace", "users_namespace.namespace_id = namespaces.id").
Where("namespaces.id = ? AND ("+
"namespaces.owner_id = ? "+
"OR (users_namespace.user_id = ? AND users_namespace.right = ?))", n.ID, user.ID, user.ID, r).
"OR (users_namespace.user_id = ? AND users_namespace.right = ?))", n.ID, u.ID, u.ID, r).
Get(&Namespace{})
if err != nil {
Log.Error("Error occurred during checkUserRights for Namespace: %s, UserRight: %d", err, r)
log.Log.Error("Error occurred during checkUserRights for Namespace: %s, UserRight: %d", err, r)
return false
}

View File

@ -1,7 +1,7 @@
package models
// Create creates a new namespace <-> user relation
func (un *NamespaceUser) Create(user *User) (err error) {
func (un *NamespaceUser) Create(u *User) (err error) {
// Reset the id
un.ID = 0

View File

@ -1,13 +1,13 @@
package models
// ReadAll gets all users who have access to a namespace
func (un *NamespaceUser) ReadAll(user *User) (interface{}, error) {
func (un *NamespaceUser) ReadAll(u *User) (interface{}, error) {
// Check if the user has access to the namespace
l, err := GetNamespaceByID(un.NamespaceID)
if err != nil {
return nil, err
}
if !l.CanRead(user) {
if !l.CanRead(u) {
return nil, ErrNeedToHaveNamespaceReadAccess{}
}

View File

@ -1,11 +1,15 @@
package models
import (
"code.vikunja.io/api/pkg/log"
)
// CanCreate checks if the user can create a new user <-> namespace relation
func (nu *NamespaceUser) CanCreate(doer *User) bool {
// Get the namespace and check if the user has write access on it
n, err := GetNamespaceByID(nu.NamespaceID)
if err != nil {
Log.Error("Error occurred during CanCreate for NamespaceUser: %s", err)
log.Log.Error("Error occurred during CanCreate for NamespaceUser: %s", err)
return false
}
return n.CanWrite(doer)
@ -16,7 +20,7 @@ func (nu *NamespaceUser) CanDelete(doer *User) bool {
// Get the namespace and check if the user has write access on it
n, err := GetNamespaceByID(nu.NamespaceID)
if err != nil {
Log.Error("Error occurred during CanCreate for NamespaceUser: %s", err)
log.Log.Error("Error occurred during CanDelete for NamespaceUser: %s", err)
return false
}
return n.CanWrite(doer)
@ -27,7 +31,7 @@ func (nu *NamespaceUser) CanUpdate(doer *User) bool {
// Get the namespace and check if the user has write access on it
n, err := GetNamespaceByID(nu.NamespaceID)
if err != nil {
Log.Error("Error occurred during CanCreate for NamespaceUser: %s", err)
log.Log.Error("Error occurred during CanUpdate for NamespaceUser: %s", err)
return false
}
return n.CanWrite(doer)

View File

@ -1,14 +1,14 @@
package models
// ReadAll implements the method to read all teams of a list
func (tl *TeamList) ReadAll(user *User) (interface{}, error) {
func (tl *TeamList) ReadAll(u *User) (interface{}, error) {
// Check if the user can read the namespace
l := &List{ID: tl.ListID}
if err := l.GetSimpleByID(); err != nil {
return nil, err
}
if !l.CanRead(user) {
return nil, ErrNeedToHaveListReadAccess{ListID: tl.ListID, UserID: user.ID}
if !l.CanRead(u) {
return nil, ErrNeedToHaveListReadAccess{ListID: tl.ListID, UserID: u.ID}
}
// Get the teams

View File

@ -1,20 +1,24 @@
package models
import (
"code.vikunja.io/api/pkg/log"
)
// CanCreate checks if the user can create a team <-> list relation
func (tl *TeamList) CanCreate(user *User) bool {
func (tl *TeamList) CanCreate(u *User) bool {
l := List{ID: tl.ListID}
if err := l.GetSimpleByID(); err != nil {
Log.Error("Error occurred during CanCreate for TeamList: %s", err)
log.Log.Error("Error occurred during CanCreate for TeamList: %s", err)
return false
}
return l.IsAdmin(user)
return l.IsAdmin(u)
}
// CanDelete checks if the user can delete a team <-> list relation
func (tl *TeamList) CanDelete(user *User) bool {
l := List{ID: tl.ListID}
if err := l.GetSimpleByID(); err != nil {
Log.Error("Error occurred during CanDelete for TeamList: %s", err)
log.Log.Error("Error occurred during CanDelete for TeamList: %s", err)
return false
}
return l.IsAdmin(user)
@ -24,7 +28,7 @@ func (tl *TeamList) CanDelete(user *User) bool {
func (tl *TeamList) CanUpdate(user *User) bool {
l := List{ID: tl.ListID}
if err := l.GetSimpleByID(); err != nil {
Log.Error("Error occurred during CanUpdate for TeamList: %s", err)
log.Log.Error("Error occurred during CanUpdate for TeamList: %s", err)
return false
}
return l.IsAdmin(user)

View File

@ -15,67 +15,67 @@ func TestTeamList(t *testing.T) {
}
// Dummyuser
user, err := GetUserByID(1)
u, err := GetUserByID(1)
assert.NoError(t, err)
// Check normal creation
assert.True(t, tl.CanCreate(&user))
err = tl.Create(&user)
assert.True(t, tl.CanCreate(&u))
err = tl.Create(&u)
assert.NoError(t, err)
// Check again
err = tl.Create(&user)
err = tl.Create(&u)
assert.Error(t, err)
assert.True(t, IsErrTeamAlreadyHasAccess(err))
// Check with wrong rights
tl2 := tl
tl2.Right = TeamRightUnknown
err = tl2.Create(&user)
err = tl2.Create(&u)
assert.Error(t, err)
assert.True(t, IsErrInvalidTeamRight(err))
// Check with inexistant team
tl3 := tl
tl3.TeamID = 3253
err = tl3.Create(&user)
err = tl3.Create(&u)
assert.Error(t, err)
assert.True(t, IsErrTeamDoesNotExist(err))
// Check with inexistant list
tl4 := tl
tl4.ListID = 3252
err = tl4.Create(&user)
err = tl4.Create(&u)
assert.Error(t, err)
assert.True(t, IsErrListDoesNotExist(err))
// Test Read all
teams, err := tl.ReadAll(&user)
teams, err := tl.ReadAll(&u)
assert.NoError(t, err)
assert.Equal(t, reflect.TypeOf(teams).Kind(), reflect.Slice)
s := reflect.ValueOf(teams)
assert.Equal(t, s.Len(), 1)
// Test Read all for nonexistant list
_, err = tl4.ReadAll(&user)
_, err = tl4.ReadAll(&u)
assert.Error(t, err)
assert.True(t, IsErrListDoesNotExist(err))
// Test Read all for a list where the user is owner of the namespace this list belongs to
tl5 := tl
tl5.ListID = 2
_, err = tl5.ReadAll(&user)
_, err = tl5.ReadAll(&u)
assert.NoError(t, err)
// Test read all for a list where the user not has access
tl6 := tl
tl6.ListID = 3
_, err = tl6.ReadAll(&user)
_, err = tl6.ReadAll(&u)
assert.Error(t, err)
assert.True(t, IsErrNeedToHaveListReadAccess(err))
// Delete
assert.True(t, tl.CanDelete(&user))
assert.True(t, tl.CanDelete(&u))
err = tl.Delete()
assert.NoError(t, err)

View File

@ -1,22 +1,26 @@
package models
import (
"code.vikunja.io/api/pkg/log"
)
// CanCreate checks if the user can add a new tem member
func (tm *TeamMember) CanCreate(user *User) bool {
return tm.IsAdmin(user)
func (tm *TeamMember) CanCreate(u *User) bool {
return tm.IsAdmin(u)
}
// CanDelete checks if the user can delete a new team member
func (tm *TeamMember) CanDelete(user *User) bool {
return tm.IsAdmin(user)
func (tm *TeamMember) CanDelete(u *User) bool {
return tm.IsAdmin(u)
}
// IsAdmin checks if the user is team admin
func (tm *TeamMember) IsAdmin(user *User) bool {
func (tm *TeamMember) IsAdmin(u *User) bool {
// A user can add a member to a team if he is admin of that team
exists, err := x.Where("user_id = ? AND team_id = ? AND admin = ?", user.ID, tm.TeamID, true).
exists, err := x.Where("user_id = ? AND team_id = ? AND admin = ?", u.ID, tm.TeamID, true).
Get(&TeamMember{})
if err != nil {
Log.Error("Error occurred during IsAdmin for TeamMember: %s", err)
log.Log.Error("Error occurred during IsAdmin for TeamMember: %s", err)
return false
}
return exists

View File

@ -1,10 +1,14 @@
package models
import (
"code.vikunja.io/api/pkg/log"
)
// CanCreate checks if one can create a new team <-> namespace relation
func (tn *TeamNamespace) CanCreate(user *User) bool {
n, err := GetNamespaceByID(tn.NamespaceID)
if err != nil {
Log.Error("Error occurred during CanCreate for TeamNamespace: %s", err)
log.Log.Error("Error occurred during CanCreate for TeamNamespace: %s", err)
return false
}
return n.IsAdmin(user)
@ -14,17 +18,17 @@ func (tn *TeamNamespace) CanCreate(user *User) bool {
func (tn *TeamNamespace) CanDelete(user *User) bool {
n, err := GetNamespaceByID(tn.NamespaceID)
if err != nil {
Log.Error("Error occurred during CanDelete for TeamNamespace: %s", err)
log.Log.Error("Error occurred during CanDelete for TeamNamespace: %s", err)
return false
}
return n.IsAdmin(user)
}
// CanUpdate checks if a user can update a team from a namespace. Only namespace admins can do that.
// CanUpdate checks if a user can update a team from a Only namespace admins can do that.
func (tn *TeamNamespace) CanUpdate(user *User) bool {
n, err := GetNamespaceByID(tn.NamespaceID)
if err != nil {
Log.Error("Error occurred during CanUpdate for TeamNamespace: %s", err)
log.Log.Error("Error occurred during CanUpdate for TeamNamespace: %s", err)
return false
}
return n.IsAdmin(user)

27
pkg/models/team_right.go Normal file
View File

@ -0,0 +1,27 @@
package models
// TeamRight defines the rights teams can have for lists/namespaces
type TeamRight int
// define unknown team right
const (
TeamRightUnknown = -1
)
// Enumerate all the team rights
const (
// Can read lists in a Team
TeamRightRead TeamRight = iota
// Can write tasks in a Team like lists and todo tasks. Cannot create new lists.
TeamRightWrite
// Can manage a list/namespace, can do everything
TeamRightAdmin
)
func (r TeamRight) isValid() error {
if r != TeamRightAdmin && r != TeamRightRead && r != TeamRightWrite {
return ErrInvalidTeamRight{r}
}
return nil
}

View File

@ -0,0 +1,58 @@
package models
import (
"code.vikunja.io/api/pkg/log"
)
// CanCreate checks if the user can create a new team
func (t *Team) CanCreate(u *User) bool {
// This is currently a dummy function, later on we could imagine global limits etc.
return true
}
// CanUpdate checks if the user can update a team
func (t *Team) CanUpdate(u *User) bool {
// Check if the current user is in the team and has admin rights in it
exists, err := x.Where("team_id = ?", t.ID).
And("user_id = ?", u.ID).
And("admin = ?", true).
Get(&TeamMember{})
if err != nil {
log.Log.Error("Error occurred during CanUpdate for Team: %s", err)
return false
}
return exists
}
// CanDelete checks if a user can delete a team
func (t *Team) CanDelete(u *User) bool {
return t.IsAdmin(u)
}
// IsAdmin returns true when the user is admin of a team
func (t *Team) IsAdmin(u *User) bool {
exists, err := x.Where("team_id = ?", t.ID).
And("user_id = ?", u.ID).
And("admin = ?", true).
Get(&TeamMember{})
if err != nil {
log.Log.Error("Error occurred during CanUpdate for Team: %s", err)
return false
}
return exists
}
// CanRead returns true if the user has read access to the team
func (t *Team) CanRead(user *User) bool {
// Check if the user is in the team
exists, err := x.Where("team_id = ?", t.ID).
And("user_id = ?", user.ID).
Get(&TeamMember{})
if err != nil {
log.Log.Error("Error occurred during CanUpdate for Team: %s", err)
return false
}
return exists
}

View File

@ -1,7 +1,7 @@
package models
import (
"code.vikunja.io/api/models/mail"
"code.vikunja.io/api/pkg/mail"
"fmt"
"github.com/go-xorm/core"
"github.com/go-xorm/xorm"

View File

@ -1,8 +1,8 @@
package models
import (
"code.vikunja.io/api/models/mail"
"code.vikunja.io/api/models/utils"
"code.vikunja.io/api/pkg/mail"
"code.vikunja.io/api/pkg/utils"
"golang.org/x/crypto/bcrypt"
)

View File

@ -1,8 +1,8 @@
package models
import (
"code.vikunja.io/api/models/mail"
"code.vikunja.io/api/models/utils"
"code.vikunja.io/api/pkg/mail"
"code.vikunja.io/api/pkg/utils"
)
// PasswordReset holds the data to reset a password

27
pkg/models/user_right.go Normal file
View File

@ -0,0 +1,27 @@
package models
// UserRight defines the rights users can have for lists/namespaces
type UserRight int
// define unknown user right
const (
UserRightUnknown = -1
)
// Enumerate all the user rights
const (
// Can read lists in a User
UserRightRead UserRight = iota
// Can write tasks in a User like lists and todo tasks. Cannot create new lists.
UserRightWrite
// Can manage a list/namespace, can do everything
UserRightAdmin
)
func (r UserRight) isValid() error {
if r != UserRightAdmin && r != UserRightRead && r != UserRightWrite {
return ErrInvalidUserRight{r}
}
return nil
}

View File

@ -1,7 +1,7 @@
package models
import (
"code.vikunja.io/api/models/utils"
"code.vikunja.io/api/pkg/utils"
"github.com/stretchr/testify/assert"
"testing"
)

View File

@ -1,7 +1,7 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/pkg/models"
"github.com/labstack/echo"
"net/http"
"strconv"

View File

@ -1,7 +1,7 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/pkg/models"
"crypto/md5"
"encoding/hex"
"github.com/dgrijalva/jwt-go"

View File

@ -1,6 +1,8 @@
package swagger
import "code.vikunja.io/api/models"
import (
"code.vikunja.io/api/pkg/models"
)
// not actually a response, just a hack to get go-swagger to include definitions
// of the various XYZOption structs

View File

@ -1,6 +1,8 @@
package swagger
import "code.vikunja.io/api/models"
import (
"code.vikunja.io/api/pkg/models"
)
// Message
// swagger:response Message

View File

@ -1,7 +1,7 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/pkg/models"
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/labstack/echo"

View File

@ -1,8 +1,8 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/routes/crud"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/routes/crud"
"github.com/labstack/echo"
"net/http"
"strconv"

View File

@ -1,8 +1,8 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/routes/crud"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/routes/crud"
"github.com/labstack/echo"
"net/http"
)

View File

@ -1,8 +1,8 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/routes/crud"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/routes/crud"
"github.com/labstack/echo"
"net/http"
"strconv"

View File

@ -1,8 +1,8 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/routes/crud"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/routes/crud"
"github.com/labstack/echo"
"net/http"
)

View File

@ -1,8 +1,8 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/routes/crud"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/routes/crud"
"github.com/labstack/echo"
"net/http"
)

View File

@ -1,8 +1,8 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/routes/crud"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/routes/crud"
"github.com/labstack/echo"
"net/http"
)

View File

@ -1,8 +1,8 @@
package v1
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/routes/crud"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/routes/crud"
"github.com/labstack/echo"
"net/http"
)

View File

@ -1,7 +1,8 @@
package crud
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/models"
"github.com/labstack/echo"
"net/http"
)
@ -24,7 +25,7 @@ func (c *WebHandler) CreateWeb(ctx echo.Context) error {
// Check rights
if !currentStruct.CanCreate(&currentUser) {
models.Log.Noticef("%s [ID: %d] tried to create while not having the rights for it", currentUser.Username, currentUser.ID)
log.Log.Noticef("%s [ID: %d] tried to create while not having the rights for it", currentUser.Username, currentUser.ID)
return echo.NewHTTPError(http.StatusForbidden)
}

View File

@ -1,7 +1,8 @@
package crud
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/models"
"github.com/labstack/echo"
"net/http"
)
@ -18,12 +19,12 @@ func (c *WebHandler) DeleteWeb(ctx echo.Context) error {
}
// Check if the user has the right to delete
user, err := models.GetCurrentUser(ctx)
currentUser, err := models.GetCurrentUser(ctx)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError)
}
if !currentStruct.CanDelete(&user) {
models.Log.Noticef("%s [ID: %d] tried to delete while not having the rights for it", user.Username, user.ID)
if !currentStruct.CanDelete(&currentUser) {
log.Log.Noticef("%s [ID: %d] tried to delete while not having the rights for it", currentUser.Username, currentUser.ID)
return echo.NewHTTPError(http.StatusForbidden)
}

View File

@ -1,7 +1,8 @@
package crud
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/models"
"github.com/labstack/echo"
"net/http"
)
@ -24,6 +25,6 @@ func HandleHTTPError(err error) *echo.HTTPError {
errDetails := a.HTTPError()
return echo.NewHTTPError(errDetails.HTTPCode, errDetails)
}
models.Log.Error(err.Error())
log.Log.Error(err.Error())
return echo.NewHTTPError(http.StatusInternalServerError)
}

View File

@ -1,7 +1,7 @@
package crud
import (
"code.vikunja.io/api/models"
"code.vikunja.io/api/pkg/models"
"github.com/labstack/echo"
"net/http"
)

Some files were not shown because too many files have changed in this diff Show More