Skip to content

Commit

Permalink
feat: List favorite repositories
Browse files Browse the repository at this point in the history
Signed-off-by: jay-dee7 <[email protected]>
  • Loading branch information
jay-dee7 committed Dec 30, 2023
1 parent a88203f commit 54cc7af
Show file tree
Hide file tree
Showing 13 changed files with 120 additions and 22 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ certs:
openssl req -x509 -newkey rsa:4096 -keyout .certs/registry.local -out .certs/registry.local.crt -sha256 -days 365 \
-subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=registry.local" -nodes

load_dummy_users:
dummy_users:
sh ./scripts/load_dummy_users.sh

reset:
Expand Down
8 changes: 6 additions & 2 deletions auth/reset_password.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,13 @@ func (a *auth) ForgotPassword(ctx echo.Context) error {
}

if !user.IsActive {
return ctx.JSON(http.StatusUnauthorized, echo.Map{
"message": "account is inactive, please check your email and verify your account",
err = fmt.Errorf("account is inactive, please check your email and verify your account")
echoErr := ctx.JSON(http.StatusUnauthorized, echo.Map{
"message": err.Error(),
})

a.logger.Log(ctx, err).Send()
return echoErr
}

opts := &WebLoginJWTOptions{
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ require (
github.com/labstack/echo-jwt/v4 v4.2.0
github.com/labstack/echo/v4 v4.11.4
github.com/multiformats/go-multiaddr v0.12.0
github.com/oklog/ulid/v2 v2.1.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0-rc5
github.com/rs/cors v1.10.1
github.com/rs/zerolog v1.31.0
github.com/sendgrid/sendgrid-go v3.14.0+incompatible
github.com/spf13/afero v1.11.0
Expand Down Expand Up @@ -158,7 +160,6 @@ require (
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.5.0 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/oklog/ulid/v2 v2.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
Expand All @@ -170,7 +171,6 @@ require (
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rs/cors v1.10.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -663,8 +663,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
Expand Down
24 changes: 24 additions & 0 deletions registry/v2/extensions/analytics.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,27 @@ func (ext *extension) RemoveRepositoryFromFavorites(ctx echo.Context) error {
ext.logger.Log(ctx, nil).Send()
return echoErr
}

func (ext *extension) ListFavoriteRepositories(ctx echo.Context) error {
ctx.Set(types.HandlerStartTime, time.Now())

user, ok := ctx.Get(string(types.UserContextKey)).(*types.User)
if !ok {
err := fmt.Errorf("missing authentication credentials")
echoErr := ctx.JSON(http.StatusForbidden, echo.Map{
"error": err.Error(),
})
ext.logger.Log(ctx, err).Send()
return echoErr
}

repos, err := ext.store.ListFavoriteRepositories(ctx.Request().Context(), user.ID)
if err != nil {
repos = make([]*types.ContainerImageRepository, 0)
}

echoErr := ctx.JSON(http.StatusOK, repos)

ext.logger.Log(ctx, nil).Send()
return echoErr
}
21 changes: 17 additions & 4 deletions registry/v2/extensions/catalog_detail.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Extenion interface {
GetUserCatalog(ctx echo.Context) error
AddRepositoryToFavorites(ctx echo.Context) error
RemoveRepositoryFromFavorites(ctx echo.Context) error
ListFavoriteRepositories(ctx echo.Context) error
}

type extension struct {
Expand Down Expand Up @@ -198,15 +199,21 @@ func (ext *extension) PublicCatalog(ctx echo.Context) error {

repositories, total, err := ext.store.GetPublicRepositories(ctx.Request().Context(), pageSize, offset)
if err != nil {
return ctx.JSON(http.StatusInternalServerError, echo.Map{
echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{
"error": err.Error(),
})

ext.logger.Log(ctx, err).Send()
return echoErr
}

return ctx.JSON(http.StatusOK, echo.Map{
echoErr := ctx.JSON(http.StatusOK, echo.Map{
"repositories": repositories,
"total": total,
})

ext.logger.Log(ctx, nil).Send()
return echoErr
}

func (ext *extension) GetUserCatalog(ctx echo.Context) error {
Expand Down Expand Up @@ -267,13 +274,19 @@ func (ext *extension) GetUserCatalog(ctx echo.Context) error {
offset,
)
if err != nil {
return ctx.JSON(http.StatusInternalServerError, echo.Map{
echoErr := ctx.JSON(http.StatusInternalServerError, echo.Map{
"error": err.Error(),
})

ext.logger.Log(ctx, err).Send()
return echoErr
}

return ctx.JSON(http.StatusOK, echo.Map{
echoErr := ctx.JSON(http.StatusOK, echo.Map{
"repositories": repositories,
"total": total,
})

ext.logger.Log(ctx, nil).Send()
return echoErr
}
10 changes: 7 additions & 3 deletions registry/v2/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ func (r *registry) ManifestExists(ctx echo.Context) error {
}

errMsg := common.RegistryErrorResponse(RegistryErrorCodeManifestBlobUnknown, err.Error(), details)
r.logger.Log(ctx, fmt.Errorf("%s", errMsg)).Send()
return ctx.NoContent(http.StatusNotFound)
echoErr := ctx.JSONBlob(http.StatusNotFound, errMsg.Bytes())
r.logger.Log(ctx, errMsg).Send()
return echoErr
}

ctx.Response().Header().Set("Content-Length", fmt.Sprintf("%d", manifest.Size))
Expand Down Expand Up @@ -792,10 +793,13 @@ func (r *registry) PushManifest(ctx echo.Context) error {
buf := &bytes.Buffer{}
_, err = io.Copy(buf, ctx.Request().Body)
if err != nil {
return ctx.JSON(http.StatusBadRequest, echo.Map{
echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{
"error": err.Error(),
"message": "failed in push manifest while io Copy",
})

r.logger.Log(ctx, nil).Send()
return echoErr
}
defer ctx.Request().Body.Close()

Expand Down
20 changes: 16 additions & 4 deletions registry/v2/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,24 @@ func (r *registry) CreateRepository(ctx echo.Context) error {
var body CreateRepositoryRequest
err := json.NewDecoder(ctx.Request().Body).Decode(&body)
if err != nil {
return ctx.JSON(http.StatusBadRequest, echo.Map{
echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{
"error": err.Error(),
"message": "error parsing request input",
})

r.logger.Log(ctx, err).Send()
return echoErr
}
defer ctx.Request().Body.Close()

if err = body.Validate(); err != nil {
return ctx.JSON(http.StatusBadRequest, echo.Map{
echoErr := ctx.JSON(http.StatusBadRequest, echo.Map{
"error": err.Error(),
"message": "invalid request body",
})

r.logger.Log(ctx, err).Send()
return echoErr
}

user := ctx.Get(string(types.UserContextKey)).(*types.User)
Expand All @@ -55,13 +61,19 @@ func (r *registry) CreateRepository(ctx echo.Context) error {
OwnerID: user.ID,
}
if err := r.store.CreateRepository(ctx.Request().Context(), repository); err != nil {
return ctx.JSON(http.StatusBadGateway, echo.Map{
echoErr := ctx.JSON(http.StatusBadGateway, echo.Map{
"error": err.Error(),
"message": "error creating repository",
})

r.logger.Log(ctx, err).Send()
return echoErr
}

return ctx.JSON(http.StatusCreated, echo.Map{
echoErr := ctx.JSON(http.StatusCreated, echo.Map{
"message": "repository created successfully",
})

r.logger.Log(ctx, nil).Send()
return echoErr
}
1 change: 1 addition & 0 deletions router/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,6 @@ func RegisterExtensionsRoutes(
group.Add(http.MethodPost, ChangeRepositoryVisibility, ext.ChangeContainerImageVisibility, middlewares...)
group.Add(http.MethodPost, CreateRepository, reg.CreateRepository, middlewares...)
group.Add(http.MethodPost, RepositoryFavorites, ext.AddRepositoryToFavorites, middlewares...)
group.Add(http.MethodGet, RepositoryFavorites, ext.ListFavoriteRepositories, middlewares...)
group.Add(http.MethodDelete, RemoveRepositoryFavorites, ext.RemoveRepositoryFromFavorites, middlewares...)
}
4 changes: 3 additions & 1 deletion router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ func Register(
webAppURL = ctx.Request().Header.Get("Origin")
}

return ctx.Redirect(http.StatusTemporaryRedirect, webAppURL)
echoErr := ctx.Redirect(http.StatusTemporaryRedirect, webAppURL)
logger.Log(ctx, nil).Send()
return echoErr
})

return e
Expand Down
39 changes: 39 additions & 0 deletions store/v1/registry/registry_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -854,3 +854,42 @@ func (s *registryStore) GetLayersLinksForManifest(
logEvent.Bool("success", true).Send()
return layers, nil
}
func (s *registryStore) ListFavoriteRepositories(
ctx context.Context,
userID uuid.UUID,
) ([]*types.ContainerImageRepository, error) {
logEvent := s.logger.Debug().Str("method", "ListFavoriteRepositories")

repositories := []*types.ContainerImageRepository{}
user := &types.User{ID: userID}
err := s.
db.
NewSelect().
Model(user).
WherePK().
Scan(ctx)

if err != nil {
return nil, err
}

if len(user.FavoriteRepositories) == 0 {
return repositories, nil
}

q := s.
db.
NewSelect().
Model(&repositories).
Where(`"r"."id" in (?)`, bun.In(user.FavoriteRepositories)).
Relation("User", func(sq *bun.SelectQuery) *bun.SelectQuery {
return sq.ExcludeColumn("password").ExcludeColumn("github_connected").ExcludeColumn("webauthn_connected")
})

if err := q.Scan(ctx); err != nil {
logEvent.Err(err).Send()
return nil, v1.WrapDatabaseError(err, v1.DatabaseOperationRead)
}

return repositories, nil
}
1 change: 1 addition & 0 deletions store/v1/registry/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,5 @@ type RegistryStore interface {
AddRepositoryToFavorites(ctx context.Context, repoID uuid.UUID, userID uuid.UUID) error
RemoveRepositoryFromFavorites(ctx context.Context, repoID uuid.UUID, userID uuid.UUID) error
GetLayersLinksForManifest(ctx context.Context, manifestDigest string) ([]*types.ContainerImageLayer, error)
ListFavoriteRepositories(ctx context.Context, userID uuid.UUID) ([]*types.ContainerImageRepository, error)
}
6 changes: 3 additions & 3 deletions store/v1/types/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ type (
Projects []*RepositoryBuildProject `bun:"rel:has-many,join:id=repository_owner_id" json:"-"`
AuthTokens []*AuthTokens `bun:"rel:has-many,join:id=owner_id" json:"-"`
// nolint:lll
FavoriteRepositories []uuid.UUID `bun:"favorite_repositories,type:uuid[],default:'{}'" json:"favorite_repositories"`
FavoriteRepositories []uuid.UUID `bun:"favorite_repositories,nullzero,type:uuid[],default:'{}'" json:"favorite_repositories"`
ID uuid.UUID `bun:"id,type:uuid,pk" json:"id,omitempty" validate:"-"`
IsActive bool `bun:"is_active" json:"is_active,omitempty" validate:"-"`
WebauthnConnected bool `bun:"webauthn_connected" json:"webauthn_connected"`
Expand All @@ -71,11 +71,11 @@ type (
AuthTokens struct {
bun.BaseModel `bun:"table:auth_tokens,alias:s" json:"-"`

Name string `bun:"name" json:"name"`
CreatedAt time.Time `bun:"created_at" json:"created_at,omitempty" validate:"-"`
ExpiresAt time.Time `bun:"expires_at" json:"expires_at,omitempty" validate:"-"`
OwnerID uuid.UUID `bun:"owner_id,type:uuid" json:"-"`
Name string `bun:"name" json:"name"`
AuthToken string `bun:"auth_token,type:text,pk" json:"-"`
OwnerID uuid.UUID `bun:"owner_id,type:uuid" json:"-"`
}

// type here is string so that we can use it with echo.Context & std context.Context
Expand Down

0 comments on commit 54cc7af

Please sign in to comment.