summaryrefslogtreecommitdiffstats
path: root/models/lfs_lock.go
blob: 52e877b156aecaee33517391b2a31fdec26f6174 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
	"fmt"
	"path"
	"strconv"
	"strings"
	"time"

	"code.gitea.io/gitea/modules/log"
	api "code.gitea.io/sdk/gitea"
	"github.com/go-xorm/xorm"
)

// LFSLock represents a git lfs lock of repository.
type LFSLock struct {
	ID      int64       `xorm:"pk autoincr"`
	Repo    *Repository `xorm:"-"`
	RepoID  int64       `xorm:"INDEX NOT NULL"`
	Owner   *User       `xorm:"-"`
	OwnerID int64       `xorm:"INDEX NOT NULL"`
	Path    string      `xorm:"TEXT"`
	Created time.Time   `xorm:"created"`
}

// BeforeInsert is invoked from XORM before inserting an object of this type.
func (l *LFSLock) BeforeInsert() {
	l.OwnerID = l.Owner.ID
	l.RepoID = l.Repo.ID
	l.Path = cleanPath(l.Path)
}

// AfterLoad is invoked from XORM after setting the values of all fields of this object.
func (l *LFSLock) AfterLoad(session *xorm.Session) {
	var err error
	l.Owner, err = getUserByID(session, l.OwnerID)
	if err != nil {
		log.Error(2, "LFS lock AfterLoad failed OwnerId[%d] not found: %v", l.OwnerID, err)
	}
	l.Repo, err = getRepositoryByID(session, l.RepoID)
	if err != nil {
		log.Error(2, "LFS lock AfterLoad failed RepoId[%d] not found: %v", l.RepoID, err)
	}
}

func cleanPath(p string) string {
	return path.Clean(p)
}

// APIFormat convert a Release to lfs.LFSLock
func (l *LFSLock) APIFormat() *api.LFSLock {
	return &api.LFSLock{
		ID:       strconv.FormatInt(l.ID, 10),
		Path:     l.Path,
		LockedAt: l.Created,
		Owner: &api.LFSLockOwner{
			Name: l.Owner.DisplayName(),
		},
	}
}

// CreateLFSLock creates a new lock.
func CreateLFSLock(lock *LFSLock) (*LFSLock, error) {
	err := CheckLFSAccessForRepo(lock.Owner, lock.Repo, AccessModeWrite)
	if err != nil {
		return nil, err
	}

	l, err := GetLFSLock(lock.Repo, lock.Path)
	if err == nil {
		return l, ErrLFSLockAlreadyExist{lock.RepoID, lock.Path}
	}
	if !IsErrLFSLockNotExist(err) {
		return nil, err
	}

	_, err = x.InsertOne(lock)
	return lock, err
}

// GetLFSLock returns release by given path.
func GetLFSLock(repo *Repository, path string) (*LFSLock, error) {
	path = cleanPath(path)
	rel := &LFSLock{RepoID: repo.ID}
	has, err := x.Where("lower(path) = ?", strings.ToLower(path)).Get(rel)
	if err != nil {
		return nil, err
	}
	if !has {
		return nil, ErrLFSLockNotExist{0, repo.ID, path}
	}
	return rel, nil
}

// GetLFSLockByID returns release by given id.
func GetLFSLockByID(id int64) (*LFSLock, error) {
	lock := new(LFSLock)
	has, err := x.ID(id).Get(lock)
	if err != nil {
		return nil, err
	} else if !has {
		return nil, ErrLFSLockNotExist{id, 0, ""}
	}
	return lock, nil
}

// GetLFSLockByRepoID returns a list of locks of repository.
func GetLFSLockByRepoID(repoID int64) (locks []*LFSLock, err error) {
	err = x.Where("repo_id = ?", repoID).Find(&locks)
	return
}

// DeleteLFSLockByID deletes a lock by given ID.
func DeleteLFSLockByID(id int64, u *User, force bool) (*LFSLock, error) {
	lock, err := GetLFSLockByID(id)
	if err != nil {
		return nil, err
	}

	err = CheckLFSAccessForRepo(u, lock.Repo, AccessModeWrite)
	if err != nil {
		return nil, err
	}

	if !force && u.ID != lock.OwnerID {
		return nil, fmt.Errorf("user doesn't own lock and force flag is not set")
	}

	_, err = x.ID(id).Delete(new(LFSLock))
	return lock, err
}

//CheckLFSAccessForRepo check needed access mode base on action
func CheckLFSAccessForRepo(u *User, repo *Repository, mode AccessMode) error {
	if u == nil {
		return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode}
	}
	has, err := HasAccess(u.ID, repo, mode)
	if err != nil {
		return err
	} else if !has {
		return ErrLFSUnauthorizedAction{repo.ID, u.DisplayName(), mode}
	}
	return nil
}