introduce RepositoryId
This commit is contained in:
parent
1fe35e14a5
commit
3172eb69d2
2 changed files with 174 additions and 101 deletions
|
@ -8,17 +8,26 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
)
|
||||
|
||||
type ActorId struct {
|
||||
Id string
|
||||
Source string
|
||||
Schema string
|
||||
Path string
|
||||
Host string
|
||||
Port string
|
||||
UnvalidatedInput string
|
||||
}
|
||||
|
||||
type PersonId struct {
|
||||
userId string
|
||||
source string
|
||||
schema string
|
||||
path string
|
||||
host string
|
||||
port string
|
||||
unvalidatedInput string
|
||||
ActorId
|
||||
}
|
||||
|
||||
type RepositoryId struct {
|
||||
ActorId
|
||||
}
|
||||
|
||||
func NewPersonId(uri string, source string) (PersonId, error) {
|
||||
|
@ -27,44 +36,71 @@ func NewPersonId(uri string, source string) (PersonId, error) {
|
|||
}
|
||||
|
||||
validatedUri, _ := url.Parse(uri)
|
||||
pathWithUserID := strings.Split(validatedUri.Path, "/")
|
||||
|
||||
if containsEmptyString(pathWithUserID) {
|
||||
pathWithUserID = removeEmptyStrings(pathWithUserID)
|
||||
pathWithActorID := strings.Split(validatedUri.Path, "/")
|
||||
if containsEmptyString(pathWithActorID) {
|
||||
pathWithActorID = removeEmptyStrings(pathWithActorID)
|
||||
}
|
||||
length := len(pathWithActorID)
|
||||
pathWithoutActorID := strings.Join(pathWithActorID[0:length-1], "/")
|
||||
id := pathWithActorID[length-1]
|
||||
|
||||
length := len(pathWithUserID)
|
||||
pathWithoutUserID := strings.Join(pathWithUserID[0:length-1], "/")
|
||||
userId := pathWithUserID[length-1]
|
||||
|
||||
actorId := PersonId{
|
||||
userId: userId,
|
||||
source: source,
|
||||
schema: validatedUri.Scheme,
|
||||
host: validatedUri.Hostname(),
|
||||
path: pathWithoutUserID,
|
||||
port: validatedUri.Port(),
|
||||
unvalidatedInput: uri,
|
||||
}
|
||||
if valid, err := actorId.IsValid(); !valid {
|
||||
result := PersonId{}
|
||||
result.Id = id
|
||||
result.Source = source
|
||||
result.Schema = validatedUri.Scheme
|
||||
result.Host = validatedUri.Hostname()
|
||||
result.Path = pathWithoutActorID
|
||||
result.Port = validatedUri.Port()
|
||||
result.UnvalidatedInput = uri
|
||||
if valid, err := result.IsValid(); !valid {
|
||||
return PersonId{}, err
|
||||
}
|
||||
|
||||
return actorId, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (id PersonId) AsUri() string {
|
||||
// TODO: tbd how an which parts can be generalized
|
||||
func NewRepositoryId(uri string, source string) (RepositoryId, error) {
|
||||
if !validation.IsAPIURL(uri) {
|
||||
return RepositoryId{}, fmt.Errorf("uri %s is not a valid repo url on this host %s", uri, setting.AppURL+"api")
|
||||
}
|
||||
|
||||
validatedUri, _ := url.Parse(uri)
|
||||
pathWithActorID := strings.Split(validatedUri.Path, "/")
|
||||
if containsEmptyString(pathWithActorID) {
|
||||
pathWithActorID = removeEmptyStrings(pathWithActorID)
|
||||
}
|
||||
length := len(pathWithActorID)
|
||||
pathWithoutActorID := strings.Join(pathWithActorID[0:length-1], "/")
|
||||
id := pathWithActorID[length-1]
|
||||
|
||||
result := RepositoryId{}
|
||||
result.Id = id
|
||||
result.Source = source
|
||||
result.Schema = validatedUri.Scheme
|
||||
result.Host = validatedUri.Hostname()
|
||||
result.Path = pathWithoutActorID
|
||||
result.Port = validatedUri.Port()
|
||||
result.UnvalidatedInput = uri
|
||||
if valid, err := result.IsValid(); !valid {
|
||||
return RepositoryId{}, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (id ActorId) AsUri() string {
|
||||
result := ""
|
||||
if id.port == "" {
|
||||
result = fmt.Sprintf("%s://%s/%s/%s", id.schema, id.host, id.path, id.userId)
|
||||
if id.Port == "" {
|
||||
result = fmt.Sprintf("%s://%s/%s/%s", id.Schema, id.Host, id.Path, id.Id)
|
||||
} else {
|
||||
result = fmt.Sprintf("%s://%s:%s/%s/%s", id.schema, id.host, id.port, id.path, id.userId)
|
||||
result = fmt.Sprintf("%s://%s:%s/%s/%s", id.Schema, id.Host, id.Port, id.Path, id.Id)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (id PersonId) AsWebfinger() string {
|
||||
result := fmt.Sprintf("@%s@%s", strings.ToLower(id.userId), strings.ToLower(id.host))
|
||||
func (id ActorId) AsWebfinger() string {
|
||||
result := fmt.Sprintf("@%s@%s", strings.ToLower(id.Id), strings.ToLower(id.Host))
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -73,22 +109,45 @@ Validate collects error strings in a slice and returns this
|
|||
*/
|
||||
func (value PersonId) Validate() []string {
|
||||
var result = []string{}
|
||||
result = append(result, validation.ValidateNotEmpty(value.userId, "userId")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.source, "source")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.schema, "schema")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.path, "path")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.host, "host")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.unvalidatedInput, "unvalidatedInput")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.Id, "userId")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.Source, "source")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.Schema, "schema")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.Path, "path")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.Host, "host")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.UnvalidatedInput, "unvalidatedInput")...)
|
||||
|
||||
result = append(result, validation.ValidateOneOf(value.source, []string{"forgejo", "gitea"})...)
|
||||
switch value.source {
|
||||
result = append(result, validation.ValidateOneOf(value.Source, []string{"forgejo", "gitea"})...)
|
||||
switch value.Source {
|
||||
case "forgejo", "gitea":
|
||||
if strings.ToLower(value.path) != "api/v1/activitypub/user-id" {
|
||||
result = append(result, fmt.Sprintf("path has to be a api path"))
|
||||
if strings.ToLower(value.Path) != "api/v1/activitypub/user-id" && strings.ToLower(value.Path) != "api/activitypub/user-id" {
|
||||
result = append(result, fmt.Sprintf("path: %q has to be a api path", value.Path))
|
||||
}
|
||||
}
|
||||
if value.unvalidatedInput != value.AsUri() {
|
||||
result = append(result, fmt.Sprintf("not all input: %q was parsed: %q", value.unvalidatedInput, value.AsUri()))
|
||||
if value.UnvalidatedInput != value.AsUri() {
|
||||
result = append(result, fmt.Sprintf("not all input: %q was parsed: %q", value.UnvalidatedInput, value.AsUri()))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (value RepositoryId) Validate() []string {
|
||||
var result = []string{}
|
||||
result = append(result, validation.ValidateNotEmpty(value.Id, "userId")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.Source, "source")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.Schema, "schema")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.Path, "path")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.Host, "host")...)
|
||||
result = append(result, validation.ValidateNotEmpty(value.UnvalidatedInput, "unvalidatedInput")...)
|
||||
|
||||
result = append(result, validation.ValidateOneOf(value.Source, []string{"forgejo", "gitea"})...)
|
||||
switch value.Source {
|
||||
case "forgejo", "gitea":
|
||||
if strings.ToLower(value.Path) != "api/v1/activitypub/repository-id" && strings.ToLower(value.Path) != "api/activitypub/repository-id" {
|
||||
result = append(result, fmt.Sprintf("path: %q has to be a api path", value.Path))
|
||||
}
|
||||
}
|
||||
if value.UnvalidatedInput != value.AsUri() {
|
||||
result = append(result, fmt.Sprintf("not all input: %q was parsed: %q", value.UnvalidatedInput, value.AsUri()))
|
||||
}
|
||||
|
||||
return result
|
||||
|
@ -106,10 +165,12 @@ func (a PersonId) IsValid() (bool, error) {
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (a PersonId) PanicIfInvalid() {
|
||||
if valid, err := a.IsValid(); !valid {
|
||||
panic(err)
|
||||
func (a RepositoryId) IsValid() (bool, error) {
|
||||
if err := a.Validate(); len(err) > 0 {
|
||||
errString := strings.Join(err, "\n")
|
||||
return false, fmt.Errorf(errString)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func containsEmptyString(ar []string) bool {
|
||||
|
|
|
@ -5,86 +5,98 @@ package forgefed
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
func TestNewPersonId(t *testing.T) {
|
||||
expected := PersonId{
|
||||
userId: "1",
|
||||
source: "forgejo",
|
||||
schema: "https",
|
||||
path: "api/v1/activitypub/user-id",
|
||||
host: "an.other.host",
|
||||
port: "",
|
||||
unvalidatedInput: "https://an.other.host/api/v1/activitypub/user-id/1",
|
||||
}
|
||||
expected := PersonId{}
|
||||
expected.Id = "1"
|
||||
expected.Source = "forgejo"
|
||||
expected.Schema = "https"
|
||||
expected.Path = "api/v1/activitypub/user-id"
|
||||
expected.Host = "an.other.host"
|
||||
expected.Port = ""
|
||||
expected.UnvalidatedInput = "https://an.other.host/api/v1/activitypub/user-id/1"
|
||||
sut, _ := NewPersonId("https://an.other.host/api/v1/activitypub/user-id/1", "forgejo")
|
||||
if sut != expected {
|
||||
t.Errorf("expected: %v\n but was: %v\n", expected, sut)
|
||||
}
|
||||
|
||||
expected = PersonId{
|
||||
userId: "1",
|
||||
source: "forgejo",
|
||||
schema: "https",
|
||||
path: "api/v1/activitypub/user-id",
|
||||
host: "an.other.host",
|
||||
port: "443",
|
||||
unvalidatedInput: "https://an.other.host:443/api/v1/activitypub/user-id/1",
|
||||
}
|
||||
expected = PersonId{}
|
||||
expected.Id = "1"
|
||||
expected.Source = "forgejo"
|
||||
expected.Schema = "https"
|
||||
expected.Path = "api/v1/activitypub/user-id"
|
||||
expected.Host = "an.other.host"
|
||||
expected.Port = "443"
|
||||
expected.UnvalidatedInput = "https://an.other.host:443/api/v1/activitypub/user-id/1"
|
||||
sut, _ = NewPersonId("https://an.other.host:443/api/v1/activitypub/user-id/1", "forgejo")
|
||||
if sut != expected {
|
||||
t.Errorf("expected: %v\n but was: %v\n", expected, sut)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPersonIdValidation(t *testing.T) {
|
||||
sut := PersonId{
|
||||
source: "forgejo",
|
||||
schema: "https",
|
||||
path: "api/v1/activitypub/user-id",
|
||||
host: "an.other.host",
|
||||
port: "",
|
||||
unvalidatedInput: "https://an.other.host/api/v1/activitypub/user-id/",
|
||||
func TestNewRepositoryId(t *testing.T) {
|
||||
setting.AppURL = "http://localhost:3000/"
|
||||
expected := RepositoryId{}
|
||||
expected.Id = "1"
|
||||
expected.Source = "forgejo"
|
||||
expected.Schema = "http"
|
||||
expected.Path = "api/activitypub/repository-id"
|
||||
expected.Host = "localhost"
|
||||
expected.Port = "3000"
|
||||
expected.UnvalidatedInput = "http://localhost:3000/api/activitypub/repository-id/1"
|
||||
sut, _ := NewRepositoryId("http://localhost:3000/api/activitypub/repository-id/1", "forgejo")
|
||||
if sut != expected {
|
||||
t.Errorf("expected: %v\n but was: %v\n", expected, sut)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPersonIdValidation(t *testing.T) {
|
||||
sut := PersonId{}
|
||||
sut.Source = "forgejo"
|
||||
sut.Schema = "https"
|
||||
sut.Path = "api/v1/activitypub/user-id"
|
||||
sut.Host = "an.other.host"
|
||||
sut.Port = ""
|
||||
sut.UnvalidatedInput = "https://an.other.host/api/v1/activitypub/user-id/"
|
||||
if sut.Validate()[0] != "Field userId may not be empty" {
|
||||
t.Errorf("validation error expected but was: %v\n", sut.Validate())
|
||||
}
|
||||
|
||||
sut = PersonId{
|
||||
userId: "1",
|
||||
source: "forgejox",
|
||||
schema: "https",
|
||||
path: "api/v1/activitypub/user-id",
|
||||
host: "an.other.host",
|
||||
port: "",
|
||||
unvalidatedInput: "https://an.other.host/api/v1/activitypub/user-id/1",
|
||||
}
|
||||
sut = PersonId{}
|
||||
sut.Id = "1"
|
||||
sut.Source = "forgejox"
|
||||
sut.Schema = "https"
|
||||
sut.Path = "api/v1/activitypub/user-id"
|
||||
sut.Host = "an.other.host"
|
||||
sut.Port = ""
|
||||
sut.UnvalidatedInput = "https://an.other.host/api/v1/activitypub/user-id/1"
|
||||
if sut.Validate()[0] != "Value forgejox is not contained in allowed values [[forgejo gitea]]" {
|
||||
t.Errorf("validation error expected but was: %v\n", sut.Validate())
|
||||
}
|
||||
|
||||
sut = PersonId{
|
||||
userId: "1",
|
||||
source: "forgejo",
|
||||
schema: "https",
|
||||
path: "api/v1/activitypub/user-idx",
|
||||
host: "an.other.host",
|
||||
port: "",
|
||||
unvalidatedInput: "https://an.other.host/api/v1/activitypub/user-id/1",
|
||||
}
|
||||
if sut.Validate()[0] != "path has to be a api path" {
|
||||
sut = PersonId{}
|
||||
sut.Id = "1"
|
||||
sut.Source = "forgejo"
|
||||
sut.Schema = "https"
|
||||
sut.Path = "path"
|
||||
sut.Host = "an.other.host"
|
||||
sut.Port = ""
|
||||
sut.UnvalidatedInput = "https://an.other.host/path/1"
|
||||
if sut.Validate()[0] != "path: \"path\" has to be a api path" {
|
||||
t.Errorf("validation error expected but was: %v\n", sut.Validate())
|
||||
}
|
||||
|
||||
sut = PersonId{
|
||||
userId: "1",
|
||||
source: "forgejo",
|
||||
schema: "https",
|
||||
path: "api/v1/activitypub/user-id",
|
||||
host: "an.other.host",
|
||||
port: "",
|
||||
unvalidatedInput: "https://an.other.host/api/v1/activitypub/user-id/1?illegal=action",
|
||||
}
|
||||
sut = PersonId{}
|
||||
sut.Id = "1"
|
||||
sut.Source = "forgejo"
|
||||
sut.Schema = "https"
|
||||
sut.Path = "api/v1/activitypub/user-id"
|
||||
sut.Host = "an.other.host"
|
||||
sut.Port = ""
|
||||
sut.UnvalidatedInput = "https://an.other.host/api/v1/activitypub/user-id/1?illegal=action"
|
||||
if sut.Validate()[0] != "not all input: \"https://an.other.host/api/v1/activitypub/user-id/1?illegal=action\" was parsed: \"https://an.other.host/api/v1/activitypub/user-id/1\"" {
|
||||
t.Errorf("validation error expected but was: %v\n", sut.Validate())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue