Add database-backed bookmarks via GraphQL
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m47s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m47s
Replace hardcoded bookmarks in the frontend with a GORM-backed Bookmark model exposed through GraphQL query and admin-only create/delete mutations. Frontend groups bookmarks by category dynamically from the store. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,12 @@ models:
|
||||
fields:
|
||||
deletedAt:
|
||||
resolver: false
|
||||
Bookmark:
|
||||
model:
|
||||
- adam-french.co.uk/backend/models.Bookmark
|
||||
fields:
|
||||
deletedAt:
|
||||
resolver: false
|
||||
JobApplication:
|
||||
model:
|
||||
- adam-french.co.uk/backend/models.JobApplication
|
||||
|
||||
22
backend/graph/bookmark.resolvers.go
Normal file
22
backend/graph/bookmark.resolvers.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package graph
|
||||
|
||||
// This file will be automatically regenerated based on the schema, any resolver
|
||||
// implementations
|
||||
// will be copied through when generating and any unknown code will be moved to the end.
|
||||
// Code generated by github.com/99designs/gqlgen version v0.17.88
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"adam-french.co.uk/backend/models"
|
||||
)
|
||||
|
||||
// ID is the resolver for the id field.
|
||||
func (r *bookmarkResolver) ID(ctx context.Context, obj *models.Bookmark) (int, error) {
|
||||
return int(obj.ID), nil
|
||||
}
|
||||
|
||||
// Bookmark returns BookmarkResolver implementation.
|
||||
func (r *Resolver) Bookmark() BookmarkResolver { return &bookmarkResolver{r} }
|
||||
|
||||
type bookmarkResolver struct{ *Resolver }
|
||||
@@ -31,6 +31,7 @@ type Config = graphql.Config[ResolverRoot, DirectiveRoot, ComplexityRoot]
|
||||
|
||||
type ResolverRoot interface {
|
||||
Activity() ActivityResolver
|
||||
Bookmark() BookmarkResolver
|
||||
Favorite() FavoriteResolver
|
||||
JobApplication() JobApplicationResolver
|
||||
Message() MessageResolver
|
||||
@@ -58,6 +59,15 @@ type ComplexityRoot struct {
|
||||
User func(childComplexity int) int
|
||||
}
|
||||
|
||||
Bookmark struct {
|
||||
Category func(childComplexity int) int
|
||||
CreatedAt func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
Link func(childComplexity int) int
|
||||
Name func(childComplexity int) int
|
||||
UpdatedAt func(childComplexity int) int
|
||||
}
|
||||
|
||||
Favorite struct {
|
||||
CreatedAt func(childComplexity int) int
|
||||
ID func(childComplexity int) int
|
||||
@@ -99,10 +109,12 @@ type ComplexityRoot struct {
|
||||
|
||||
Mutation struct {
|
||||
CreateActivity func(childComplexity int, input model.CreateActivityInput) int
|
||||
CreateBookmark func(childComplexity int, input model.CreateBookmarkInput) int
|
||||
CreateFavorite func(childComplexity int, input model.CreateFavoriteInput) int
|
||||
CreateJobApplication func(childComplexity int, input model.CreateJobApplicationInput) int
|
||||
CreatePost func(childComplexity int, input model.CreatePostInput) int
|
||||
CreateUser func(childComplexity int, input model.CreateUserInput) int
|
||||
DeleteBookmark func(childComplexity int, id int) int
|
||||
DeleteJobApplication func(childComplexity int, id int) int
|
||||
DeletePost func(childComplexity int, id int) int
|
||||
DeleteUser func(childComplexity int, id int) int
|
||||
@@ -125,6 +137,7 @@ type ComplexityRoot struct {
|
||||
|
||||
Query struct {
|
||||
Activities func(childComplexity int) int
|
||||
Bookmarks func(childComplexity int) int
|
||||
Favorites func(childComplexity int) int
|
||||
GiteaFeed func(childComplexity int) int
|
||||
JobApplication func(childComplexity int, id int) int
|
||||
@@ -205,6 +218,9 @@ type ComplexityRoot struct {
|
||||
type ActivityResolver interface {
|
||||
ID(ctx context.Context, obj *models.Activity) (int, error)
|
||||
}
|
||||
type BookmarkResolver interface {
|
||||
ID(ctx context.Context, obj *models.Bookmark) (int, error)
|
||||
}
|
||||
type FavoriteResolver interface {
|
||||
ID(ctx context.Context, obj *models.Favorite) (int, error)
|
||||
}
|
||||
@@ -230,6 +246,8 @@ type MutationResolver interface {
|
||||
CreateActivity(ctx context.Context, input model.CreateActivityInput) (*models.Activity, error)
|
||||
CreateJobApplication(ctx context.Context, input model.CreateJobApplicationInput) (*models.JobApplication, error)
|
||||
UpdateJobApplication(ctx context.Context, id int, input model.UpdateJobApplicationInput) (*models.JobApplication, error)
|
||||
CreateBookmark(ctx context.Context, input model.CreateBookmarkInput) (*models.Bookmark, error)
|
||||
DeleteBookmark(ctx context.Context, id int) (*models.Bookmark, error)
|
||||
DeleteJobApplication(ctx context.Context, id int) (bool, error)
|
||||
}
|
||||
type PostResolver interface {
|
||||
@@ -249,6 +267,7 @@ type QueryResolver interface {
|
||||
GiteaFeed(ctx context.Context) (*model.GiteaFeedItem, error)
|
||||
SteamStatus(ctx context.Context) (*model.SteamStatus, error)
|
||||
Me(ctx context.Context) (*models.User, error)
|
||||
Bookmarks(ctx context.Context) ([]*models.Bookmark, error)
|
||||
JobApplications(ctx context.Context) ([]*models.JobApplication, error)
|
||||
JobApplication(ctx context.Context, id int) (*models.JobApplication, error)
|
||||
}
|
||||
@@ -320,6 +339,43 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
return e.ComplexityRoot.AuthPayload.User(childComplexity), true
|
||||
|
||||
case "Bookmark.category":
|
||||
if e.ComplexityRoot.Bookmark.Category == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Bookmark.Category(childComplexity), true
|
||||
case "Bookmark.createdAt":
|
||||
if e.ComplexityRoot.Bookmark.CreatedAt == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Bookmark.CreatedAt(childComplexity), true
|
||||
case "Bookmark.id":
|
||||
if e.ComplexityRoot.Bookmark.ID == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Bookmark.ID(childComplexity), true
|
||||
case "Bookmark.link":
|
||||
if e.ComplexityRoot.Bookmark.Link == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Bookmark.Link(childComplexity), true
|
||||
case "Bookmark.name":
|
||||
if e.ComplexityRoot.Bookmark.Name == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Bookmark.Name(childComplexity), true
|
||||
case "Bookmark.updatedAt":
|
||||
if e.ComplexityRoot.Bookmark.UpdatedAt == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Bookmark.UpdatedAt(childComplexity), true
|
||||
|
||||
case "Favorite.createdAt":
|
||||
if e.ComplexityRoot.Favorite.CreatedAt == nil {
|
||||
break
|
||||
@@ -497,6 +553,17 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Mutation.CreateActivity(childComplexity, args["input"].(model.CreateActivityInput)), true
|
||||
case "Mutation.createBookmark":
|
||||
if e.ComplexityRoot.Mutation.CreateBookmark == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_createBookmark_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Mutation.CreateBookmark(childComplexity, args["input"].(model.CreateBookmarkInput)), true
|
||||
case "Mutation.createFavorite":
|
||||
if e.ComplexityRoot.Mutation.CreateFavorite == nil {
|
||||
break
|
||||
@@ -541,6 +608,17 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Mutation.CreateUser(childComplexity, args["input"].(model.CreateUserInput)), true
|
||||
case "Mutation.deleteBookmark":
|
||||
if e.ComplexityRoot.Mutation.DeleteBookmark == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Mutation_deleteBookmark_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Mutation.DeleteBookmark(childComplexity, args["id"].(int)), true
|
||||
case "Mutation.deleteJobApplication":
|
||||
if e.ComplexityRoot.Mutation.DeleteJobApplication == nil {
|
||||
break
|
||||
@@ -674,6 +752,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Query.Activities(childComplexity), true
|
||||
case "Query.bookmarks":
|
||||
if e.ComplexityRoot.Query.Bookmarks == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.ComplexityRoot.Query.Bookmarks(childComplexity), true
|
||||
case "Query.favorites":
|
||||
if e.ComplexityRoot.Query.Favorites == nil {
|
||||
break
|
||||
@@ -974,6 +1058,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
ec := newExecutionContext(opCtx, e, make(chan graphql.DeferredResult))
|
||||
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
|
||||
ec.unmarshalInputCreateActivityInput,
|
||||
ec.unmarshalInputCreateBookmarkInput,
|
||||
ec.unmarshalInputCreateFavoriteInput,
|
||||
ec.unmarshalInputCreateJobApplicationInput,
|
||||
ec.unmarshalInputCreatePostInput,
|
||||
@@ -1055,7 +1140,7 @@ func newExecutionContext(
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed "schema/activity.graphql" "schema/auth.graphql" "schema/favorite.graphql" "schema/gitea.graphql" "schema/job_application.graphql" "schema/message.graphql" "schema/post.graphql" "schema/rowing.graphql" "schema/schema.graphql" "schema/spotify.graphql" "schema/steam.graphql" "schema/user.graphql"
|
||||
//go:embed "schema/activity.graphql" "schema/auth.graphql" "schema/bookmark.graphql" "schema/favorite.graphql" "schema/gitea.graphql" "schema/job_application.graphql" "schema/message.graphql" "schema/post.graphql" "schema/rowing.graphql" "schema/schema.graphql" "schema/spotify.graphql" "schema/steam.graphql" "schema/user.graphql"
|
||||
var sourcesFS embed.FS
|
||||
|
||||
func sourceData(filename string) string {
|
||||
@@ -1069,6 +1154,7 @@ func sourceData(filename string) string {
|
||||
var sources = []*ast.Source{
|
||||
{Name: "schema/activity.graphql", Input: sourceData("schema/activity.graphql"), BuiltIn: false},
|
||||
{Name: "schema/auth.graphql", Input: sourceData("schema/auth.graphql"), BuiltIn: false},
|
||||
{Name: "schema/bookmark.graphql", Input: sourceData("schema/bookmark.graphql"), BuiltIn: false},
|
||||
{Name: "schema/favorite.graphql", Input: sourceData("schema/favorite.graphql"), BuiltIn: false},
|
||||
{Name: "schema/gitea.graphql", Input: sourceData("schema/gitea.graphql"), BuiltIn: false},
|
||||
{Name: "schema/job_application.graphql", Input: sourceData("schema/job_application.graphql"), BuiltIn: false},
|
||||
@@ -1097,6 +1183,17 @@ func (ec *executionContext) field_Mutation_createActivity_args(ctx context.Conte
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_createBookmark_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNCreateBookmarkInput2adamᚑfrenchᚗcoᚗukᚋbackendᚋgraphᚋmodelᚐCreateBookmarkInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args["input"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_createFavorite_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
@@ -1141,6 +1238,17 @@ func (ec *executionContext) field_Mutation_createUser_args(ctx context.Context,
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_deleteBookmark_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
arg0, err := graphql.ProcessArgField(ctx, rawArgs, "id", ec.unmarshalNID2int)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args["id"] = arg0
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Mutation_deleteJobApplication_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
@@ -1544,6 +1652,180 @@ func (ec *executionContext) fieldContext_AuthPayload_user(_ context.Context, fie
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Bookmark_id(ctx context.Context, field graphql.CollectedField, obj *models.Bookmark) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_Bookmark_id,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return ec.Resolvers.Bookmark().ID(ctx, obj)
|
||||
},
|
||||
nil,
|
||||
ec.marshalNID2int,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Bookmark_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Bookmark",
|
||||
Field: field,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type ID does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Bookmark_createdAt(ctx context.Context, field graphql.CollectedField, obj *models.Bookmark) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_Bookmark_createdAt,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return obj.CreatedAt, nil
|
||||
},
|
||||
nil,
|
||||
ec.marshalNTime2timeᚐTime,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Bookmark_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Bookmark",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Time does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Bookmark_updatedAt(ctx context.Context, field graphql.CollectedField, obj *models.Bookmark) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_Bookmark_updatedAt,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return obj.UpdatedAt, nil
|
||||
},
|
||||
nil,
|
||||
ec.marshalNTime2timeᚐTime,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Bookmark_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Bookmark",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type Time does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Bookmark_category(ctx context.Context, field graphql.CollectedField, obj *models.Bookmark) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_Bookmark_category,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return obj.Category, nil
|
||||
},
|
||||
nil,
|
||||
ec.marshalNString2string,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Bookmark_category(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Bookmark",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Bookmark_name(ctx context.Context, field graphql.CollectedField, obj *models.Bookmark) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_Bookmark_name,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return obj.Name, nil
|
||||
},
|
||||
nil,
|
||||
ec.marshalNString2string,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Bookmark_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Bookmark",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Bookmark_link(ctx context.Context, field graphql.CollectedField, obj *models.Bookmark) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_Bookmark_link,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return obj.Link, nil
|
||||
},
|
||||
nil,
|
||||
ec.marshalNString2string,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Bookmark_link(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Bookmark",
|
||||
Field: field,
|
||||
IsMethod: false,
|
||||
IsResolver: false,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
return nil, errors.New("field of type String does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Favorite_id(ctx context.Context, field graphql.CollectedField, obj *models.Favorite) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
@@ -2994,6 +3276,116 @@ func (ec *executionContext) fieldContext_Mutation_updateJobApplication(ctx conte
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_createBookmark(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_Mutation_createBookmark,
|
||||
func(ctx context.Context) (any, error) {
|
||||
fc := graphql.GetFieldContext(ctx)
|
||||
return ec.Resolvers.Mutation().CreateBookmark(ctx, fc.Args["input"].(model.CreateBookmarkInput))
|
||||
},
|
||||
nil,
|
||||
ec.marshalNBookmark2ᚖadamᚑfrenchᚗcoᚗukᚋbackendᚋmodelsᚐBookmark,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Mutation_createBookmark(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "id":
|
||||
return ec.fieldContext_Bookmark_id(ctx, field)
|
||||
case "createdAt":
|
||||
return ec.fieldContext_Bookmark_createdAt(ctx, field)
|
||||
case "updatedAt":
|
||||
return ec.fieldContext_Bookmark_updatedAt(ctx, field)
|
||||
case "category":
|
||||
return ec.fieldContext_Bookmark_category(ctx, field)
|
||||
case "name":
|
||||
return ec.fieldContext_Bookmark_name(ctx, field)
|
||||
case "link":
|
||||
return ec.fieldContext_Bookmark_link(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type Bookmark", field.Name)
|
||||
},
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = ec.Recover(ctx, r)
|
||||
ec.Error(ctx, err)
|
||||
}
|
||||
}()
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
if fc.Args, err = ec.field_Mutation_createBookmark_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return fc, err
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_deleteBookmark(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_Mutation_deleteBookmark,
|
||||
func(ctx context.Context) (any, error) {
|
||||
fc := graphql.GetFieldContext(ctx)
|
||||
return ec.Resolvers.Mutation().DeleteBookmark(ctx, fc.Args["id"].(int))
|
||||
},
|
||||
nil,
|
||||
ec.marshalNBookmark2ᚖadamᚑfrenchᚗcoᚗukᚋbackendᚋmodelsᚐBookmark,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Mutation_deleteBookmark(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Mutation",
|
||||
Field: field,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "id":
|
||||
return ec.fieldContext_Bookmark_id(ctx, field)
|
||||
case "createdAt":
|
||||
return ec.fieldContext_Bookmark_createdAt(ctx, field)
|
||||
case "updatedAt":
|
||||
return ec.fieldContext_Bookmark_updatedAt(ctx, field)
|
||||
case "category":
|
||||
return ec.fieldContext_Bookmark_category(ctx, field)
|
||||
case "name":
|
||||
return ec.fieldContext_Bookmark_name(ctx, field)
|
||||
case "link":
|
||||
return ec.fieldContext_Bookmark_link(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type Bookmark", field.Name)
|
||||
},
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = ec.Recover(ctx, r)
|
||||
ec.Error(ctx, err)
|
||||
}
|
||||
}()
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
if fc.Args, err = ec.field_Mutation_deleteBookmark_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return fc, err
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Mutation_deleteJobApplication(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
@@ -3774,6 +4166,49 @@ func (ec *executionContext) fieldContext_Query_me(_ context.Context, field graph
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Query_bookmarks(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
ec.OperationContext,
|
||||
field,
|
||||
ec.fieldContext_Query_bookmarks,
|
||||
func(ctx context.Context) (any, error) {
|
||||
return ec.Resolvers.Query().Bookmarks(ctx)
|
||||
},
|
||||
nil,
|
||||
ec.marshalNBookmark2ᚕᚖadamᚑfrenchᚗcoᚗukᚋbackendᚋmodelsᚐBookmarkᚄ,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_Query_bookmarks(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "Query",
|
||||
Field: field,
|
||||
IsMethod: true,
|
||||
IsResolver: true,
|
||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||
switch field.Name {
|
||||
case "id":
|
||||
return ec.fieldContext_Bookmark_id(ctx, field)
|
||||
case "createdAt":
|
||||
return ec.fieldContext_Bookmark_createdAt(ctx, field)
|
||||
case "updatedAt":
|
||||
return ec.fieldContext_Bookmark_updatedAt(ctx, field)
|
||||
case "category":
|
||||
return ec.fieldContext_Bookmark_category(ctx, field)
|
||||
case "name":
|
||||
return ec.fieldContext_Bookmark_name(ctx, field)
|
||||
case "link":
|
||||
return ec.fieldContext_Bookmark_link(ctx, field)
|
||||
}
|
||||
return nil, fmt.Errorf("no field named %q was found under type Bookmark", field.Name)
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Query_jobApplications(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
return graphql.ResolveField(
|
||||
ctx,
|
||||
@@ -6398,6 +6833,50 @@ func (ec *executionContext) unmarshalInputCreateActivityInput(ctx context.Contex
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputCreateBookmarkInput(ctx context.Context, obj any) (model.CreateBookmarkInput, error) {
|
||||
var it model.CreateBookmarkInput
|
||||
if obj == nil {
|
||||
return it, nil
|
||||
}
|
||||
|
||||
asMap := map[string]any{}
|
||||
for k, v := range obj.(map[string]any) {
|
||||
asMap[k] = v
|
||||
}
|
||||
|
||||
fieldsInOrder := [...]string{"category", "name", "link"}
|
||||
for _, k := range fieldsInOrder {
|
||||
v, ok := asMap[k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch k {
|
||||
case "category":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("category"))
|
||||
data, err := ec.unmarshalNString2string(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Category = data
|
||||
case "name":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
|
||||
data, err := ec.unmarshalNString2string(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Name = data
|
||||
case "link":
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("link"))
|
||||
data, err := ec.unmarshalNString2string(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
it.Link = data
|
||||
}
|
||||
}
|
||||
return it, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalInputCreateFavoriteInput(ctx context.Context, obj any) (model.CreateFavoriteInput, error) {
|
||||
var it model.CreateFavoriteInput
|
||||
if obj == nil {
|
||||
@@ -6873,6 +7352,101 @@ func (ec *executionContext) _AuthPayload(ctx context.Context, sel ast.SelectionS
|
||||
return out
|
||||
}
|
||||
|
||||
var bookmarkImplementors = []string{"Bookmark"}
|
||||
|
||||
func (ec *executionContext) _Bookmark(ctx context.Context, sel ast.SelectionSet, obj *models.Bookmark) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, bookmarkImplementors)
|
||||
|
||||
out := graphql.NewFieldSet(fields)
|
||||
deferred := make(map[string]*graphql.FieldSet)
|
||||
for i, field := range fields {
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("Bookmark")
|
||||
case "id":
|
||||
field := field
|
||||
|
||||
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
}
|
||||
}()
|
||||
res = ec._Bookmark_id(ctx, field, obj)
|
||||
if res == graphql.Null {
|
||||
atomic.AddUint32(&fs.Invalids, 1)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
if field.Deferrable != nil {
|
||||
dfs, ok := deferred[field.Deferrable.Label]
|
||||
di := 0
|
||||
if ok {
|
||||
dfs.AddField(field)
|
||||
di = len(dfs.Values) - 1
|
||||
} else {
|
||||
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
|
||||
deferred[field.Deferrable.Label] = dfs
|
||||
}
|
||||
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
|
||||
return innerFunc(ctx, dfs)
|
||||
})
|
||||
|
||||
// don't run the out.Concurrently() call below
|
||||
out.Values[i] = graphql.Null
|
||||
continue
|
||||
}
|
||||
|
||||
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||
case "createdAt":
|
||||
out.Values[i] = ec._Bookmark_createdAt(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&out.Invalids, 1)
|
||||
}
|
||||
case "updatedAt":
|
||||
out.Values[i] = ec._Bookmark_updatedAt(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&out.Invalids, 1)
|
||||
}
|
||||
case "category":
|
||||
out.Values[i] = ec._Bookmark_category(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&out.Invalids, 1)
|
||||
}
|
||||
case "name":
|
||||
out.Values[i] = ec._Bookmark_name(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&out.Invalids, 1)
|
||||
}
|
||||
case "link":
|
||||
out.Values[i] = ec._Bookmark_link(ctx, field, obj)
|
||||
if out.Values[i] == graphql.Null {
|
||||
atomic.AddUint32(&out.Invalids, 1)
|
||||
}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch(ctx)
|
||||
if out.Invalids > 0 {
|
||||
return graphql.Null
|
||||
}
|
||||
|
||||
atomic.AddInt32(&ec.Deferred, int32(len(deferred)))
|
||||
|
||||
for label, dfs := range deferred {
|
||||
ec.ProcessDeferredGroup(graphql.DeferredGroup{
|
||||
Label: label,
|
||||
Path: graphql.GetPath(ctx),
|
||||
FieldSet: dfs,
|
||||
Context: ctx,
|
||||
})
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
var favoriteImplementors = []string{"Favorite"}
|
||||
|
||||
func (ec *executionContext) _Favorite(ctx context.Context, sel ast.SelectionSet, obj *models.Favorite) graphql.Marshaler {
|
||||
@@ -7360,6 +7934,20 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "createBookmark":
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_createBookmark(ctx, field)
|
||||
})
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "deleteBookmark":
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_deleteBookmark(ctx, field)
|
||||
})
|
||||
if out.Values[i] == graphql.Null {
|
||||
out.Invalids++
|
||||
}
|
||||
case "deleteJobApplication":
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._Mutation_deleteJobApplication(ctx, field)
|
||||
@@ -7765,6 +8353,28 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
|
||||
func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||
}
|
||||
|
||||
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
|
||||
case "bookmarks":
|
||||
field := field
|
||||
|
||||
innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
}
|
||||
}()
|
||||
res = ec._Query_bookmarks(ctx, field)
|
||||
if res == graphql.Null {
|
||||
atomic.AddUint32(&fs.Invalids, 1)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
rrm := func(ctx context.Context) graphql.Marshaler {
|
||||
return ec.OperationContext.RootResolverMiddleware(ctx,
|
||||
func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||
}
|
||||
|
||||
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
|
||||
case "jobApplications":
|
||||
field := field
|
||||
@@ -8828,6 +9438,36 @@ func (ec *executionContext) marshalNAuthPayload2ᚖadamᚑfrenchᚗcoᚗukᚋbac
|
||||
return ec._AuthPayload(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNBookmark2adamᚑfrenchᚗcoᚗukᚋbackendᚋmodelsᚐBookmark(ctx context.Context, sel ast.SelectionSet, v models.Bookmark) graphql.Marshaler {
|
||||
return ec._Bookmark(ctx, sel, &v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNBookmark2ᚕᚖadamᚑfrenchᚗcoᚗukᚋbackendᚋmodelsᚐBookmarkᚄ(ctx context.Context, sel ast.SelectionSet, v []*models.Bookmark) graphql.Marshaler {
|
||||
ret := graphql.MarshalSliceConcurrently(ctx, len(v), 0, false, func(ctx context.Context, i int) graphql.Marshaler {
|
||||
fc := graphql.GetFieldContext(ctx)
|
||||
fc.Result = &v[i]
|
||||
return ec.marshalNBookmark2ᚖadamᚑfrenchᚗcoᚗukᚋbackendᚋmodelsᚐBookmark(ctx, sel, v[i])
|
||||
})
|
||||
|
||||
for _, e := range ret {
|
||||
if e == graphql.Null {
|
||||
return graphql.Null
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalNBookmark2ᚖadamᚑfrenchᚗcoᚗukᚋbackendᚋmodelsᚐBookmark(ctx context.Context, sel ast.SelectionSet, v *models.Bookmark) graphql.Marshaler {
|
||||
if v == nil {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow")
|
||||
}
|
||||
return graphql.Null
|
||||
}
|
||||
return ec._Bookmark(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v any) (bool, error) {
|
||||
res, err := graphql.UnmarshalBoolean(v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
@@ -8849,6 +9489,11 @@ func (ec *executionContext) unmarshalNCreateActivityInput2adamᚑfrenchᚗcoᚗu
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNCreateBookmarkInput2adamᚑfrenchᚗcoᚗukᚋbackendᚋgraphᚋmodelᚐCreateBookmarkInput(ctx context.Context, v any) (model.CreateBookmarkInput, error) {
|
||||
res, err := ec.unmarshalInputCreateBookmarkInput(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalNCreateFavoriteInput2adamᚑfrenchᚗcoᚗukᚋbackendᚋgraphᚋmodelᚐCreateFavoriteInput(ctx context.Context, v any) (model.CreateFavoriteInput, error) {
|
||||
res, err := ec.unmarshalInputCreateFavoriteInput(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
|
||||
@@ -18,6 +18,12 @@ type CreateActivityInput struct {
|
||||
Link *string `json:"link,omitempty"`
|
||||
}
|
||||
|
||||
type CreateBookmarkInput struct {
|
||||
Category string `json:"category"`
|
||||
Name string `json:"name"`
|
||||
Link string `json:"link"`
|
||||
}
|
||||
|
||||
type CreateFavoriteInput struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -349,6 +349,33 @@ func (r *mutationResolver) UpdateJobApplication(ctx context.Context, id int, inp
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
// CreateBookmark is the resolver for the createBookmark field.
|
||||
func (r *mutationResolver) CreateBookmark(ctx context.Context, input model.CreateBookmarkInput) (*models.Bookmark, error) {
|
||||
if !IsAdminFromCtx(ctx) {
|
||||
return nil, fmt.Errorf("admin access required")
|
||||
}
|
||||
bookmark := models.Bookmark{Category: input.Category, Name: input.Name, Link: input.Link}
|
||||
if err := r.Store.DB.Create(&bookmark).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &bookmark, nil
|
||||
}
|
||||
|
||||
// DeleteBookmark is the resolver for the deleteBookmark field.
|
||||
func (r *mutationResolver) DeleteBookmark(ctx context.Context, id int) (*models.Bookmark, error) {
|
||||
if !IsAdminFromCtx(ctx) {
|
||||
return nil, fmt.Errorf("admin access required")
|
||||
}
|
||||
var bookmark models.Bookmark
|
||||
if err := r.Store.DB.First(&bookmark, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := r.Store.DB.Delete(&bookmark).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &bookmark, nil
|
||||
}
|
||||
|
||||
// DeleteJobApplication is the resolver for the deleteJobApplication field.
|
||||
func (r *mutationResolver) DeleteJobApplication(ctx context.Context, id int) (bool, error) {
|
||||
if !IsAdminFromCtx(ctx) {
|
||||
@@ -571,6 +598,19 @@ func (r *queryResolver) Me(ctx context.Context) (*models.User, error) {
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
// Bookmarks is the resolver for the bookmarks field.
|
||||
func (r *queryResolver) Bookmarks(ctx context.Context) ([]*models.Bookmark, error) {
|
||||
var bookmarks []models.Bookmark
|
||||
if err := r.Store.DB.Order("category ASC, created_at ASC").Find(&bookmarks).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]*models.Bookmark, len(bookmarks))
|
||||
for i := range bookmarks {
|
||||
result[i] = &bookmarks[i]
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// JobApplications is the resolver for the jobApplications field.
|
||||
func (r *queryResolver) JobApplications(ctx context.Context) ([]*models.JobApplication, error) {
|
||||
if !IsAdminFromCtx(ctx) {
|
||||
|
||||
14
backend/graph/schema/bookmark.graphql
Normal file
14
backend/graph/schema/bookmark.graphql
Normal file
@@ -0,0 +1,14 @@
|
||||
type Bookmark {
|
||||
id: ID!
|
||||
createdAt: Time!
|
||||
updatedAt: Time!
|
||||
category: String!
|
||||
name: String!
|
||||
link: String!
|
||||
}
|
||||
|
||||
input CreateBookmarkInput {
|
||||
category: String!
|
||||
name: String!
|
||||
link: String!
|
||||
}
|
||||
@@ -14,6 +14,7 @@ type Query {
|
||||
giteaFeed: GiteaFeedItem
|
||||
steamStatus: SteamStatus
|
||||
me: User
|
||||
bookmarks: [Bookmark!]!
|
||||
jobApplications: [JobApplication!]!
|
||||
jobApplication(id: ID!): JobApplication
|
||||
}
|
||||
@@ -32,5 +33,7 @@ type Mutation {
|
||||
createActivity(input: CreateActivityInput!): Activity!
|
||||
createJobApplication(input: CreateJobApplicationInput!): JobApplication!
|
||||
updateJobApplication(id: ID!, input: UpdateJobApplicationInput!): JobApplication!
|
||||
createBookmark(input: CreateBookmarkInput!): Bookmark!
|
||||
deleteBookmark(id: ID!): Bookmark!
|
||||
deleteJobApplication(id: ID!): Boolean!
|
||||
}
|
||||
|
||||
@@ -67,6 +67,16 @@ type Rowing struct {
|
||||
Calories float64 `json:"calories"`
|
||||
}
|
||||
|
||||
type Bookmark struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"deletedAt"`
|
||||
Category string `gorm:"not null" json:"category"`
|
||||
Name string `gorm:"not null" json:"name"`
|
||||
Link string `gorm:"not null" json:"link"`
|
||||
}
|
||||
|
||||
type JobApplication struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
|
||||
@@ -39,6 +39,7 @@ func migrateDatabase(db *gorm.DB) error {
|
||||
&models.Rowing{},
|
||||
&models.Message{},
|
||||
&models.JobApplication{},
|
||||
&models.Bookmark{},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -15,6 +15,7 @@ export const useHomeDataStore = defineStore("homeData", () => {
|
||||
const rowingSessions = ref([]);
|
||||
const gitFeed = ref(null);
|
||||
const steamStatus = ref(null);
|
||||
const bookmarks = ref([]);
|
||||
const radioLive = ref(false);
|
||||
|
||||
async function fetchAll() {
|
||||
@@ -27,6 +28,7 @@ export const useHomeDataStore = defineStore("homeData", () => {
|
||||
activities { id type name link createdAt }
|
||||
spotifyRecent { track { name album { name images { url } } artists { name } } playedAt }
|
||||
rowingSessions { id date time distance timePer500m calories }
|
||||
bookmarks { id category name link }
|
||||
giteaFeed { avatarUrl repoUrl repoName opType commitMessage createdAt }
|
||||
steamStatus { online recentGames { appId name playtime2Weeks playtimeForever headerImageUrl } }
|
||||
me { id username admin }
|
||||
@@ -38,6 +40,7 @@ export const useHomeDataStore = defineStore("homeData", () => {
|
||||
favorites.value = data.favorites;
|
||||
activities.value = data.activities;
|
||||
spotifyRecent.value = data.spotifyRecent || [];
|
||||
bookmarks.value = data.bookmarks || [];
|
||||
rowingSessions.value = data.rowingSessions;
|
||||
gitFeed.value = data.giteaFeed || null;
|
||||
steamStatus.value = data.steamStatus || null;
|
||||
@@ -64,6 +67,7 @@ export const useHomeDataStore = defineStore("homeData", () => {
|
||||
loaded,
|
||||
error,
|
||||
me,
|
||||
bookmarks,
|
||||
posts,
|
||||
favorites,
|
||||
activities,
|
||||
|
||||
@@ -1,240 +1,18 @@
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
import { useHomeDataStore } from "@/stores/homeData";
|
||||
|
||||
const links = [
|
||||
[
|
||||
"Reading Links",
|
||||
[
|
||||
{
|
||||
name: "Substack",
|
||||
link: "https://substack.com/",
|
||||
},
|
||||
{
|
||||
name: "Medium",
|
||||
link: "https://medium.com/",
|
||||
},
|
||||
{
|
||||
name: "4Chan",
|
||||
link: "https://www.4chan.org/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Job Links",
|
||||
[
|
||||
{
|
||||
name: "LinkedIn",
|
||||
link: "https://www.linkedin.com/",
|
||||
},
|
||||
{
|
||||
name: "Jack and Jill",
|
||||
link: "https://app.jackandjill.ai",
|
||||
},
|
||||
{
|
||||
name: "LinkedIn",
|
||||
link: "https://www.linkedin.com/",
|
||||
},
|
||||
{
|
||||
name: "Prospects",
|
||||
link: "https://www.prospects.ac.uk/",
|
||||
},
|
||||
{
|
||||
name: "GOV",
|
||||
link: "https://findajob.dwp.gov.uk",
|
||||
},
|
||||
{
|
||||
name: "Glassdoor",
|
||||
link: "https://www.glassdoor.co.uk/",
|
||||
},
|
||||
{
|
||||
name: "Indeed",
|
||||
link: "https://www.indeed.co.uk/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Learning Links",
|
||||
[
|
||||
{
|
||||
name: "Leetcode",
|
||||
link: "https://leetcode.com/",
|
||||
},
|
||||
{
|
||||
name: "ISLP",
|
||||
link: "https://hastie.su.domains/ISLP/ISLP_website.pdf.download.html",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Social Links",
|
||||
[
|
||||
{
|
||||
name: "Outlook",
|
||||
link: "https://outlook.live.com/",
|
||||
},
|
||||
{
|
||||
name: "Gmail",
|
||||
link: "https://mail.google.com/",
|
||||
},
|
||||
{
|
||||
name: "Whatsapp",
|
||||
link: "https://web.whatsapp.com/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Radio links",
|
||||
[
|
||||
{
|
||||
name: "Radio Helsinki",
|
||||
link: "https://www.radiohelsinki.fi/",
|
||||
},
|
||||
{
|
||||
name: "Palanga Street Radio",
|
||||
link: "https://palanga.live/",
|
||||
},
|
||||
{
|
||||
name: "IDA Radio",
|
||||
link: "https://idaidaida.net/",
|
||||
},
|
||||
{
|
||||
name: "Tīrkultūra",
|
||||
link: "https://www.tirkultura.lv/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Hacking Links",
|
||||
[
|
||||
{
|
||||
name: "pwn.college",
|
||||
link: "https://pwn.college/",
|
||||
},
|
||||
{
|
||||
name: "OSINT Framework",
|
||||
link: "https://osintframework.com/",
|
||||
},
|
||||
{
|
||||
name: "OverTheWire",
|
||||
link: "https://overthewire.org/",
|
||||
},
|
||||
{
|
||||
name: "TryHackMe",
|
||||
link: "https://tryhackme.com/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Chinese Links",
|
||||
[
|
||||
{
|
||||
name: "MDBG Chinese Dictionary",
|
||||
link: "https://www.mdbg.net/chinese/dictionary",
|
||||
},
|
||||
{
|
||||
name: "Stroke Order",
|
||||
link: "https://www.strokeorder.com/",
|
||||
},
|
||||
{
|
||||
name: "HSK 1 Peking University",
|
||||
link: "https://youtube.com/playlist?list=PLVWfp7qXLmKVfSUkucXErLncKn-JqgBbK&si=2ytO3inS8-iOAOx2",
|
||||
},
|
||||
{
|
||||
name: "Stroke Order",
|
||||
link: "https://www.strokeorder.com/",
|
||||
},
|
||||
{
|
||||
name: "Offbeat Mandarin",
|
||||
link: "https://www.youtube.com/@OffbeatMandarin",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Art links",
|
||||
[
|
||||
{
|
||||
name: "Frida Kahlo",
|
||||
link: "https://www.fridakahlo.org/",
|
||||
},
|
||||
{
|
||||
name: "Cameron's World",
|
||||
link: "https://www.cameronsworld.net/",
|
||||
},
|
||||
{
|
||||
name: "Neocities",
|
||||
link: "https://neocities.org/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Vue links",
|
||||
[
|
||||
{
|
||||
name: "Vue",
|
||||
link: "https://vuejs.org/guide/introduction.html",
|
||||
},
|
||||
{
|
||||
name: "Vue Router",
|
||||
link: "https://router.vuejs.org/introduction.html",
|
||||
},
|
||||
{
|
||||
name: "Pinia",
|
||||
link: "https://pinia.vuejs.org/introduction.html",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Go links",
|
||||
[
|
||||
{
|
||||
name: "Golang",
|
||||
link: "https://golang.org/doc/",
|
||||
},
|
||||
{
|
||||
name: "Gin Gonic",
|
||||
link: "https://gin-gonic.com/en/docs/introduction/",
|
||||
},
|
||||
{
|
||||
name: "GORM",
|
||||
link: "https://gorm.io/gen/index.html",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Doc links",
|
||||
[
|
||||
{
|
||||
name: "Rust",
|
||||
link: "https://doc.rust-lang.org/stable/book/index.html",
|
||||
},
|
||||
{
|
||||
name: "Javascript",
|
||||
link: "https://developer.mozilla.org/en-US/docs/Web/JavaScript",
|
||||
},
|
||||
{
|
||||
name: "Python",
|
||||
link: "https://docs.python.org/3/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Article links",
|
||||
[
|
||||
{
|
||||
name: "Go and GORM",
|
||||
link: "https://medium.com/@chaewonkong/learn-go-understanding-and-implementing-foreign-keys-with-gorm-6d7608e1dbf6",
|
||||
},
|
||||
{
|
||||
name: "JWT Auth in GO",
|
||||
link: "https://medium.com/monstar-lab-bangladesh-engineering/jwt-auth-in-go-dde432440924",
|
||||
},
|
||||
{
|
||||
name: "Websockets in GO",
|
||||
link: "https://medium.com/@tanngontn/golang-gin-framework-with-normal-websocket-and-websocket-with-producer-is-rabbitmq-guide-93cad7d290f7",
|
||||
},
|
||||
],
|
||||
],
|
||||
];
|
||||
const homeData = useHomeDataStore();
|
||||
|
||||
const groupedBookmarks = computed(() => {
|
||||
const groups = {};
|
||||
for (const b of homeData.bookmarks) {
|
||||
if (!groups[b.category]) groups[b.category] = [];
|
||||
groups[b.category].push(b);
|
||||
}
|
||||
return Object.entries(groups);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -245,9 +23,9 @@ const links = [
|
||||
<div class="w-full h-fit">
|
||||
<LinkTable
|
||||
class="flex flex-col flex-wrap"
|
||||
v-for="link in links"
|
||||
:title="link[0]"
|
||||
:items="link[1]"
|
||||
v-for="group in groupedBookmarks"
|
||||
:title="group[0]"
|
||||
:items="group[1]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user