~netlandish/links

2e2333e83fb9d78cc98654256b9d122ae2337418 — Peter Sanchez 7 days ago 83119f6
Updating deleteLink to use link hash instead of ID
M api/api_test.go => api/api_test.go +3 -4
@@ 897,17 897,16 @@ func TestAPI(t *testing.T) {

		var result GraphQLResponse
		op := gqlclient.NewOperation(
			`mutation DeleteLink($id: Int!) {
				deleteLink(id: $id) {
			`mutation DeleteLink($hash: String!) {
				deleteLink(hash: $hash) {
					success
					objectId
				}
			}`)
		op.Var("id", orgLink.ID)
		op.Var("hash", orgLink.Hash)
		err = links.Execute(ctx, op, &result)
		c.NoError(err)
		c.Equal(true, result.DeleteLink.Success)

	})

	t.Run("add domain error", func(t *testing.T) {

M api/graph/generated.go => api/graph/generated.go +9 -9
@@ 225,7 225,7 @@ type ComplexityRoot struct {
		CompleteRegister       func(childComplexity int, input *model.CompleteRegisterInput) int
		ConfirmMember          func(childComplexity int, key string) int
		DeleteDomain           func(childComplexity int, id int) int
		DeleteLink             func(childComplexity int, id int) int
		DeleteLink             func(childComplexity int, hash string) int
		DeleteLinkShort        func(childComplexity int, id int) int
		DeleteListing          func(childComplexity int, id int) int
		DeleteListingLink      func(childComplexity int, id int) int


@@ 438,7 438,7 @@ type MutationResolver interface {
	AddOrganization(ctx context.Context, input model.OrganizationInput) (*models.Organization, error)
	AddLink(ctx context.Context, input *model.LinkInput) (*models.OrgLink, error)
	UpdateLink(ctx context.Context, input *model.UpdateLinkInput) (*models.OrgLink, error)
	DeleteLink(ctx context.Context, id int) (*model.DeletePayload, error)
	DeleteLink(ctx context.Context, hash string) (*model.DeletePayload, error)
	AddNote(ctx context.Context, input *model.NoteInput) (*models.OrgLink, error)
	AddMember(ctx context.Context, input *model.MemberInput) (*model.AddMemberPayload, error)
	DeleteMember(ctx context.Context, orgSlug string, email string) (*model.AddMemberPayload, error)


@@ 1364,7 1364,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
			return 0, false
		}

		return e.complexity.Mutation.DeleteLink(childComplexity, args["id"].(int)), true
		return e.complexity.Mutation.DeleteLink(childComplexity, args["hash"].(string)), true

	case "Mutation.deleteLinkShort":
		if e.complexity.Mutation.DeleteLinkShort == nil {


@@ 2972,15 2972,15 @@ func (ec *executionContext) field_Mutation_deleteLinkShort_args(ctx context.Cont
func (ec *executionContext) field_Mutation_deleteLink_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
	var err error
	args := map[string]interface{}{}
	var arg0 int
	if tmp, ok := rawArgs["id"]; ok {
		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
		arg0, err = ec.unmarshalNInt2int(ctx, tmp)
	var arg0 string
	if tmp, ok := rawArgs["hash"]; ok {
		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hash"))
		arg0, err = ec.unmarshalNString2string(ctx, tmp)
		if err != nil {
			return nil, err
		}
	}
	args["id"] = arg0
	args["hash"] = arg0
	return args, nil
}



@@ 9236,7 9236,7 @@ func (ec *executionContext) _Mutation_deleteLink(ctx context.Context, field grap
	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
		directive0 := func(rctx context.Context) (interface{}, error) {
			ctx = rctx // use context from middleware stack in children
			return ec.resolvers.Mutation().DeleteLink(rctx, fc.Args["id"].(int))
			return ec.resolvers.Mutation().DeleteLink(rctx, fc.Args["hash"].(string))
		}
		directive1 := func(ctx context.Context) (interface{}, error) {
			scope, err := ec.unmarshalNAccessScope2linksᚋapiᚋgraphᚋmodelᚐAccessScope(ctx, "LINKS")

M api/graph/schema.graphqls => api/graph/schema.graphqls +1 -1
@@ 751,7 751,7 @@ type Mutation {
    "Add/Edit/Delete organization link. Also used edit/delete notes"
    addLink(input: LinkInput): OrgLink! @access(scope: LINKS, kind: RW)
    updateLink(input: UpdateLinkInput): OrgLink! @access(scope: LINKS, kind: RW)
    deleteLink(id: Int!): DeletePayload! @access(scope: LINKS, kind: RW)
    deleteLink(hash: String!): DeletePayload! @access(scope: LINKS, kind: RW)
    
    "Add organization note"
    addNote(input: NoteInput): OrgLink! @access(scope: LINKS, kind: RW)

M api/graph/schema.resolvers.go => api/graph/schema.resolvers.go +4 -5
@@ 515,7 515,7 @@ func (r *mutationResolver) UpdateLink(ctx context.Context, input *model.UpdateLi
}

// DeleteLink is the resolver for the deleteLink field.
func (r *mutationResolver) DeleteLink(ctx context.Context, id int) (*model.DeletePayload, error) {
func (r *mutationResolver) DeleteLink(ctx context.Context, hash string) (*model.DeletePayload, error) {
	tokenUser := oauth2.ForContext(ctx)
	if tokenUser == nil {
		return nil, valid.ErrAuthorization


@@ 528,7 528,7 @@ func (r *mutationResolver) DeleteLink(ctx context.Context, id int) (*model.Delet
	}
	opts := &database.FilterOptions{
		Filter: sq.And{
			sq.Expr("ol.id = ?", id),
			sq.Expr("ol.hash = ?", hash),
		},
		Limit: 1,
	}


@@ 546,8 546,7 @@ func (r *mutationResolver) DeleteLink(ctx context.Context, id int) (*model.Delet
	}
	link := orgLinks[0]

	// If the user is not the link creator, check
	// if it's the org owner
	// If the user is not the link creator, verify org write permissions
	if link.UserID != int(user.ID) {
		opts = &database.FilterOptions{
			Filter: sq.And{


@@ 576,7 575,7 @@ func (r *mutationResolver) DeleteLink(ctx context.Context, id int) (*model.Delet
		}
	}

	deletedID := strconv.Itoa(link.ID)
	deletedID := link.Hash
	visibility := link.Visibility
	baseURLID := int(link.BaseURLID.Int64)
	err = link.Delete(ctx)

M core/routes.go => core/routes.go +10 -10
@@ 89,8 89,8 @@ func (s *Service) RegisterRoutes() {
	s.Group.POST("/add", s.OrgLinksCreate).Name = s.RouteName("link_create_post")
	s.Group.GET("/read/:id", s.OrgLinkAsReadToggle).Name = s.RouteName("link_mark_as_read")
	s.Group.GET("/star/:id", s.OrgLinkStarToggle).Name = s.RouteName("link_star_toggle")
	s.Group.GET("/link/:id/delete", s.OrgLinkDelete).Name = s.RouteName("link_delete")
	s.Group.POST("/link/:id/delete", s.OrgLinkDelete).Name = s.RouteName("link_delete")
	s.Group.GET("/link/:hash/delete", s.OrgLinkDelete).Name = s.RouteName("link_delete")
	s.Group.POST("/link/:hash/delete", s.OrgLinkDelete).Name = s.RouteName("link_delete")
	s.Group.GET("/link/:id/edit", s.OrgLinkUpdate).Name = s.RouteName("link_edit")
	s.Group.POST("/link/:id/edit", s.OrgLinkUpdate).Name = s.RouteName("link_edit_post")
	s.Group.GET("/qr/:hash/detail", s.QRManageDetail).Name = s.RouteName("qr_manage_detail")


@@ 2320,8 2320,8 @@ func (s *Service) OrgLinkDetail(c echo.Context) error {

// OrgLinkDelete ...
func (s *Service) OrgLinkDelete(c echo.Context) error {
	id, err := strconv.Atoi(c.Param("id"))
	if err != nil {
	hash := c.Param("hash")
	if hash == "" {
		return echo.NotFoundHandler(c)
	}
	gctx := c.(*server.Context)


@@ 2339,14 2339,14 @@ func (s *Service) OrgLinkDelete(c echo.Context) error {

		var result GraphQLResponse
		op := gqlclient.NewOperation(
			`mutation DeleteLink($id: Int!) {
				deleteLink(id: $id) {
			`mutation DeleteLink($hash: String!) {
				deleteLink(hash: $hash) {
					success
					objectId
				}
			}`)
		op.Var("id", id)
		err = links.Execute(c.Request().Context(), op, &result)
		op.Var("hash", hash)
		err := links.Execute(c.Request().Context(), op, &result)
		if err != nil {
			return err
		}


@@ 2367,7 2367,7 @@ func (s *Service) OrgLinkDelete(c echo.Context) error {
	// NOTE: All these validations already happen in the resolver for the POST request
	opts := &database.FilterOptions{
		Filter: sq.And{
			sq.Expr("ol.id = ?", id),
			sq.Expr("ol.hash = ?", hash),
		},
		Limit: 1,
	}


@@ 2400,7 2400,7 @@ func (s *Service) OrgLinkDelete(c echo.Context) error {
	pd.Data["message"] = lt.Translate("Do you really whant to delete this bookmark?")
	gmap := gobwebs.Map{
		"pd":   pd,
		"url":  c.Echo().Reverse(s.RouteName("link_delete"), link.ID),
		"url":  c.Echo().Reverse(s.RouteName("link_delete"), link.Hash),
		"back": c.Echo().Reverse(s.RouteName("home_link_list")),
	}
	return s.Render(c, http.StatusOK, "element_delete.html", gmap)

M core/routes_test.go => core/routes_test.go +3 -3
@@ 328,9 328,9 @@ func TestHandlers(t *testing.T) {
			Context: e.NewContext(request, recorder),
			User:    loggedInUser,
		}
		ctx.SetPath("/link/:id/delete")
		ctx.SetParamNames("id")
		ctx.SetParamValues("1")
		ctx.SetPath("/link/:hash/delete")
		ctx.SetParamNames("hash")
		ctx.SetParamValues("ABCDEFG")
		err = test.MakeRequestWithDomain(srv, coreService.OrgLinkDelete, ctx, domains[0])
		c.NoError(err)
		c.Equal(http.StatusMovedPermanently, recorder.Code)

M templates/link_list.html => templates/link_list.html +1 -1
@@ 137,7 137,7 @@
                </a>

                <!-- Delete -->
                <a class="icon-link tooltip-link" href="{{reverse "core:link_delete" .ID}}" data-tooltip="{{$.pd.Data.delete}}">
                <a class="icon-link tooltip-link" href="{{reverse "core:link_delete" .Hash}}" data-tooltip="{{$.pd.Data.delete}}">
                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6" style="width:20px;">
                        <path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
                    </svg>