vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
|
c717d4eb
Keenan Nemetz
13d ago
|
1 | package web |
| 2 | ||
| 3 | // What a viewer may do in one repository, in the terms the pages use. | |
| 4 | // | |
| 5 | // Each function is one rule from forge/access, stated once. The tab that is | |
| 6 | // shown, the button that is rendered, and the handler that would accept the write | |
| 7 | // all ask the same question here, so a control cannot be offered to somebody the | |
| 8 | // writer would refuse. | |
| 9 | // | |
| 10 | // The account name passed in is always the one a credential resolved to. Nothing | |
| 11 | // here takes a name from a form field. | |
| 12 | ||
|
d37d301f
Keenan Nemetz
19h ago
|
13 | import "rodent.software/vole/forge/access" |
|
c717d4eb
Keenan Nemetz
13d ago
|
14 | |
| 15 | // canDiscuss reports whether the account may take part in a repository at all: | |
| 16 | // file an issue, comment on one, or open a change request. Those are one | |
| 17 | // capability because discussing is what each of them is. | |
| 18 | func canDiscuss(acl *access.ACL, name string) bool { | |
| 19 | return acl != nil && name != "" && acl.CanDiscuss(name) | |
| 20 | } | |
| 21 | ||
| 22 | // canOpenChangeRequest reports whether the account may open a change request. It | |
| 23 | // is separate from canDiscuss because a repository can allow discussion while | |
| 24 | // only trusting established contributors with requests. | |
| 25 | func canOpenChangeRequest(acl *access.ACL, name string) bool { | |
| 26 | return acl != nil && name != "" && acl.CanOpenRequest(name) | |
| 27 | } | |
| 28 | ||
| 29 | // canMaintain reports whether the account holds the repository's maintainer | |
| 30 | // capability: triaging other people's issues, approving change requests, | |
| 31 | // allowing contributor CI, and managing releases. It says nothing about whose | |
| 32 | // item is in front of it; that is canTriage's job. | |
| 33 | func canMaintain(acl *access.ACL, name string) bool { | |
| 34 | return acl != nil && name != "" && acl.CanTriage(name) | |
| 35 | } | |
| 36 | ||
| 37 | // canTriage reports whether the account may manage one issue or change request: | |
| 38 | // a maintainer may triage any of them, and its author may manage their own. | |
| 39 | func canTriage(acl *access.ACL, name, author string) bool { | |
| 40 | return canMaintain(acl, name) || (author != "" && author == name) | |
| 41 | } | |
| 42 | ||
| 43 | // canApprove reports whether the account may approve change requests here. It | |
| 44 | // does not decide whether one request may be approved: approving your own is a | |
| 45 | // separate rule (see canApproveRequest), because the reader is owed the reason | |
| 46 | // that applies rather than a general refusal. | |
| 47 | func canApprove(acl *access.ACL, name string) bool { | |
| 48 | return canMaintain(acl, name) | |
| 49 | } | |
| 50 | ||
| 51 | // canApproveRequest is canApprove plus the self-approval rule. It is what the | |
| 52 | // approve control is drawn from. | |
| 53 | func canApproveRequest(acl *access.ACL, name, author string) bool { | |
| 54 | return canApprove(acl, name) && name != author | |
| 55 | } | |
| 56 | ||
|
38b30251
Keenan Nemetz
13d ago
|
57 | // canMerge reports whether the account may land a change request here. It is the |
| 58 | // approve capability: landing is the act of accepting the review, so the accounts | |
| 59 | // that may approve may merge. The author is not excluded — merging your own request | |
| 60 | // after somebody else approved it is the point of separating the two — and whether | |
| 61 | // this approval count is satisfied is the gate's question, not this one. | |
| 62 | func canMerge(acl *access.ACL, name string) bool { | |
| 63 | return canMaintain(acl, name) | |
| 64 | } | |
| 65 | ||
|
c717d4eb
Keenan Nemetz
13d ago
|
66 | // contributorOnly reports whether the account is a contributor and nothing more, |
| 67 | // so every branch it may push is inside its own contrib/ namespace. The rule | |
| 68 | // matters to change requests: a contributor must open one from their own branch, | |
| 69 | // because that is the only branch the pre-receive hook would have let them write. | |
| 70 | func contributorOnly(acl *access.ACL, name string) bool { | |
| 71 | return acl != nil && name != "" && acl.RoleFor(name) == access.Contribute | |
| 72 | } | |
| 73 | ||
| 74 | // canAdminister reports whether the account holds the repository's admin role. | |
| 75 | // An instance admin gets this on every repository through EffectiveRole, which is | |
| 76 | // why the read path asks canRead rather than this. | |
| 77 | func canAdminister(acl *access.ACL, name string) bool { | |
| 78 | return acl != nil && name != "" && acl.Can(name, access.Admin) | |
| 79 | } | |
| 80 | ||
| 81 | // canModerateComment reports whether the account may edit or delete a comment: | |
| 82 | // the account that wrote it, or an admin repairing a thread. | |
| 83 | func canModerateComment(acl *access.ACL, name, author string) bool { | |
| 84 | if acl == nil || name == "" { | |
| 85 | return false | |
| 86 | } | |
| 87 | return name == author || acl.RoleFor(name).AtLeast(access.Admin) | |
| 88 | } |