1
Fork 0

Working permissions (logic reused from other components), album and photo sidebars now fully functional. Will require some testing, and need to adjust for people pages.

This commit is contained in:
Peter - Ubuntu dual boot 2021-09-18 11:58:21 +01:00
parent 47692bfcf8
commit 4ee8040364
10 changed files with 287 additions and 111 deletions

View File

@ -154,9 +154,10 @@ type ComplexityRoot struct {
MoveImageFaces func(childComplexity int, imageFaceIDs []int, destinationFaceGroupID int) int
ProtectShareToken func(childComplexity int, token string, password *string) int
RecognizeUnlabeledFaces func(childComplexity int) int
ResetAlbumCover func(childComplexity int, albumID int) int
ScanAll func(childComplexity int) int
ScanUser func(childComplexity int, userID int) int
SetAlbumCoverID func(childComplexity int, albumID int, coverID *int) int
SetAlbumCover func(childComplexity int, coverID int) int
SetFaceGroupLabel func(childComplexity int, faceGroupID int, label *string) int
SetPeriodicScanInterval func(childComplexity int, interval int) int
SetScannerConcurrentWorkers func(childComplexity int, workers int) int
@ -314,7 +315,8 @@ type MutationResolver interface {
SetPeriodicScanInterval(ctx context.Context, interval int) (int, error)
SetScannerConcurrentWorkers(ctx context.Context, workers int) (int, error)
ChangeUserPreferences(ctx context.Context, language *string) (*models.UserPreferences, error)
SetAlbumCoverID(ctx context.Context, albumID int, coverID *int) (*models.Album, error)
ResetAlbumCover(ctx context.Context, albumID int) (*models.Album, error)
SetAlbumCover(ctx context.Context, coverID int) (*models.Album, error)
SetFaceGroupLabel(ctx context.Context, faceGroupID int, label *string) (*models.FaceGroup, error)
CombineFaceGroups(ctx context.Context, destinationFaceGroupID int, sourceFaceGroupID int) (*models.FaceGroup, error)
MoveImageFaces(ctx context.Context, imageFaceIDs []int, destinationFaceGroupID int) (*models.FaceGroup, error)
@ -929,6 +931,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.RecognizeUnlabeledFaces(childComplexity), true
case "Mutation.resetAlbumCover":
if e.complexity.Mutation.ResetAlbumCover == nil {
break
}
args, err := ec.field_Mutation_resetAlbumCover_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.ResetAlbumCover(childComplexity, args["albumID"].(int)), true
case "Mutation.scanAll":
if e.complexity.Mutation.ScanAll == nil {
break
@ -948,17 +962,17 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.ScanUser(childComplexity, args["userId"].(int)), true
case "Mutation.setAlbumCoverID":
if e.complexity.Mutation.SetAlbumCoverID == nil {
case "Mutation.setAlbumCover":
if e.complexity.Mutation.SetAlbumCover == nil {
break
}
args, err := ec.field_Mutation_setAlbumCoverID_args(context.TODO(), rawArgs)
args, err := ec.field_Mutation_setAlbumCover_args(context.TODO(), rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.SetAlbumCoverID(childComplexity, args["albumID"].(int), args["coverID"].(*int)), true
return e.complexity.Mutation.SetAlbumCover(childComplexity, args["coverID"].(int)), true
case "Mutation.setFaceGroupLabel":
if e.complexity.Mutation.SetFaceGroupLabel == nil {
@ -1788,8 +1802,10 @@ type Mutation {
changeUserPreferences(language: String): UserPreferences! @isAuthorized
"Assign a cover image to an album, set coverID to -1 to remove the current one"
setAlbumCoverID(albumID: ID!, coverID: Int): Album! @isAuthorized
"Reset the assigned cover photo for an album"
resetAlbumCover(albumID: ID!): Album! @isAuthorized
"Assign a cover photo to an album"
setAlbumCover(coverID: ID!): Album! @isAuthorized
"Assign a label to a face group, set label to null to remove the current one"
setFaceGroupLabel(faceGroupID: ID!, label: String): FaceGroup! @isAuthorized
@ -2376,6 +2392,21 @@ func (ec *executionContext) field_Mutation_protectShareToken_args(ctx context.Co
return args, nil
}
func (ec *executionContext) field_Mutation_resetAlbumCover_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["albumID"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("albumID"))
arg0, err = ec.unmarshalNID2int(ctx, tmp)
if err != nil {
return nil, err
}
}
args["albumID"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_scanUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@ -2391,27 +2422,18 @@ func (ec *executionContext) field_Mutation_scanUser_args(ctx context.Context, ra
return args, nil
}
func (ec *executionContext) field_Mutation_setAlbumCoverID_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
func (ec *executionContext) field_Mutation_setAlbumCover_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["albumID"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("albumID"))
if tmp, ok := rawArgs["coverID"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("coverID"))
arg0, err = ec.unmarshalNID2int(ctx, tmp)
if err != nil {
return nil, err
}
}
args["albumID"] = arg0
var arg1 *int
if tmp, ok := rawArgs["coverID"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("coverID"))
arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp)
if err != nil {
return nil, err
}
}
args["coverID"] = arg1
args["coverID"] = arg0
return args, nil
}
@ -5949,7 +5971,7 @@ func (ec *executionContext) _Mutation_changeUserPreferences(ctx context.Context,
return ec.marshalNUserPreferences2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐUserPreferences(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation_setAlbumCoverID(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
func (ec *executionContext) _Mutation_resetAlbumCover(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
@ -5966,7 +5988,7 @@ func (ec *executionContext) _Mutation_setAlbumCoverID(ctx context.Context, field
ctx = graphql.WithFieldContext(ctx, fc)
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.field_Mutation_setAlbumCoverID_args(ctx, rawArgs)
args, err := ec.field_Mutation_resetAlbumCover_args(ctx, rawArgs)
if err != nil {
ec.Error(ctx, err)
return graphql.Null
@ -5975,7 +5997,69 @@ func (ec *executionContext) _Mutation_setAlbumCoverID(ctx context.Context, field
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().SetAlbumCoverID(rctx, args["albumID"].(int), args["coverID"].(*int))
return ec.resolvers.Mutation().ResetAlbumCover(rctx, args["albumID"].(int))
}
directive1 := func(ctx context.Context) (interface{}, error) {
if ec.directives.IsAuthorized == nil {
return nil, errors.New("directive isAuthorized is not implemented")
}
return ec.directives.IsAuthorized(ctx, nil, directive0)
}
tmp, err := directive1(rctx)
if err != nil {
return nil, graphql.ErrorOnPath(ctx, err)
}
if tmp == nil {
return nil, nil
}
if data, ok := tmp.(*models.Album); ok {
return data, nil
}
return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/photoview/photoview/api/graphql/models.Album`, tmp)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*models.Album)
fc.Result = res
return ec.marshalNAlbum2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐAlbum(ctx, field.Selections, res)
}
func (ec *executionContext) _Mutation_setAlbumCover(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Mutation",
Field: field,
Args: nil,
IsMethod: true,
IsResolver: true,
}
ctx = graphql.WithFieldContext(ctx, fc)
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.field_Mutation_setAlbumCover_args(ctx, rawArgs)
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
fc.Args = args
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().SetAlbumCover(rctx, args["coverID"].(int))
}
directive1 := func(ctx context.Context) (interface{}, error) {
if ec.directives.IsAuthorized == nil {
@ -10855,8 +10939,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
invalids++
}
case "setAlbumCoverID":
out.Values[i] = ec._Mutation_setAlbumCoverID(ctx, field)
case "resetAlbumCover":
out.Values[i] = ec._Mutation_resetAlbumCover(ctx, field)
if out.Values[i] == graphql.Null {
invalids++
}
case "setAlbumCover":
out.Values[i] = ec._Mutation_setAlbumCover(ctx, field)
if out.Values[i] == graphql.Null {
invalids++
}

View File

@ -17,7 +17,7 @@ type Album struct {
Owners []User `gorm:"many2many:user_albums;constraint:OnDelete:CASCADE;"`
Path string `gorm:"not null"`
PathHash string `gorm:"unique"`
CoverID int `gorm:"index;default:-1;"`
CoverID int `gorm:"index;"`
}
func (a *Album) FilePath() string {

View File

@ -152,7 +152,7 @@ func (r *albumResolver) Thumbnail(ctx context.Context, obj *models.Album) (*mode
fmt.Print(obj.CoverID)
if obj.CoverID == -1 {
if obj.CoverID == 0 {
if err := r.Database.Raw(`
WITH recursive sub_albums AS (
SELECT * FROM albums AS root WHERE id = ?
@ -265,7 +265,8 @@ func (r *albumResolver) Path(ctx context.Context, obj *models.Album) ([]*models.
return album_path, nil
}
func (r *mutationResolver) SetAlbumCoverID(ctx context.Context, albumID int, coverID *int) (*models.Album, error) {
// Takes album_id, resets album.cover_id to 0 (null)
func (r *mutationResolver) ResetAlbumCover(ctx context.Context, albumID int) (*models.Album, error) {
user := auth.UserFromContext(ctx)
if user == nil {
return nil, errors.New("unauthorized")
@ -276,9 +277,41 @@ func (r *mutationResolver) SetAlbumCoverID(ctx context.Context, albumID int, cov
return nil, err
}
//
// var album models.Album
//
ownsAlbum, err := user.OwnsAlbum(r.Database, &album)
if err != nil {
return nil, err
}
if !ownsAlbum {
return nil, errors.New("forbidden")
}
if err := r.Database.Model(&album).Update("cover_id", 0).Error; err != nil {
return nil, err
}
return &album, nil
}
// Takes media.id, finds parent album, sets album.cover_id to media.id (must be a more efficient way of doing this, but it works)
func (r *mutationResolver) SetAlbumCover(ctx context.Context, coverID int) (*models.Album, error) {
user := auth.UserFromContext(ctx)
if user == nil {
return nil, errors.New("unauthorized")
}
var media models.Media
if err := r.Database.Find(&media, coverID).Error; err != nil {
return nil, err
}
var album models.Album
if err := r.Database.Find(&album, &media.AlbumID).Error; err != nil {
return nil, err
}
ownsAlbum, err := user.OwnsAlbum(r.Database, &album)
if err != nil {
return nil, err
@ -292,16 +325,5 @@ func (r *mutationResolver) SetAlbumCoverID(ctx context.Context, albumID int, cov
return nil, err
}
// var faceGroup models.FaceGroup
// if err := db.Where("id = ?", faceGroupID).Find(&faceGroup).Error; err != nil {
// return nil, err
// }
//
// return &faceGroup, nil
//
// if err := r.Database.Model(faceGroup).Update("label", label).Error; err != nil {
// return nil, err
// }
return &album, nil
}

View File

@ -134,8 +134,10 @@ type Mutation {
changeUserPreferences(language: String): UserPreferences! @isAuthorized
"Assign a cover image to an album, set coverID to -1 to remove the current one"
setAlbumCoverID(albumID: ID!, coverID: Int): Album! @isAuthorized
"Reset the assigned cover photo for an album"
resetAlbumCover(albumID: ID!): Album! @isAuthorized
"Assign a cover photo to an album"
setAlbumCover(coverID: ID!): Album! @isAuthorized
"Assign a label to a face group, set label to null to remove the current one"
setFaceGroupLabel(faceGroupID: ID!, label: String): FaceGroup! @isAuthorized

View File

@ -5,33 +5,41 @@ import { useTranslation } from 'react-i18next'
import { SidebarSection, SidebarSectionTitle } from './SidebarComponents'
import {
setAlbumCoverID,
setAlbumCoverIDVariables,
} from './__generated__/setAlbumCoverID'
setAlbumCover,
setAlbumCoverVariables,
} from './__generated__/setAlbumCover'
import {
resetAlbumCover,
resetAlbumCoverVariables,
} from './__generated__/resetAlbumCover'
const SET_ALBUM_COVER_ID_MUTATION = gql`
mutation setAlbumCoverID($albumID: ID!, $coverID: Int!) {
setAlbumCoverID(albumID: $albumID, coverID: $coverID) {
const RESET_ALBUM_COVER_MUTATION = gql`
mutation resetAlbumCover($albumID: ID!) {
resetAlbumCover(albumID: $albumID) {
id
}
}
`
const SET_ALBUM_COVER_MUTATION = gql`
mutation setAlbumCover($coverID: ID!) {
setAlbumCover(coverID: $coverID) {
coverID
}
}
`
type SidebarPhotoCoverProps = {
id: string
cover_id: string
}
export const SidebarPhotoCover = ({ id, cover_id }: SidebarPhotoCoverProps) => {
export const SidebarPhotoCover = ({ cover_id }: SidebarPhotoCoverProps) => {
const { t } = useTranslation()
const [setAlbumCoverID, { loading }] = useMutation<
setAlbumCoverID,
setAlbumCoverIDVariables
>(SET_ALBUM_COVER_ID_MUTATION, {
const [setAlbumCover, { loading }] = useMutation<
setAlbumCover,
setAlbumCoverVariables
>(SET_ALBUM_COVER_MUTATION, {
variables: {
albumID: id,
coverID: cover_id,
},
})
@ -39,7 +47,7 @@ export const SidebarPhotoCover = ({ id, cover_id }: SidebarPhotoCoverProps) => {
return (
<SidebarSection>
<SidebarSectionTitle>
{t('sidebar.album.cover_photo', 'Cover Photo')}
{t('sidebar.album.cover_photo', 'Album cover')}
</SidebarSectionTitle>
<div>
<table className="border-collapse w-full">
@ -50,9 +58,8 @@ export const SidebarPhotoCover = ({ id, cover_id }: SidebarPhotoCoverProps) => {
className="text-green-500 font-bold uppercase text-xs"
disabled={loading}
onClick={() => {
setAlbumCoverID({
setAlbumCover({
variables: {
albumID: id,
coverID: cover_id,
},
})
@ -78,13 +85,12 @@ type SidebarAlbumCoverProps = {
export const SidebarAlbumCover = ({ id }: SidebarAlbumCoverProps) => {
const { t } = useTranslation()
const [setAlbumCoverID, { loading }] = useMutation<
setAlbumCoverID,
setAlbumCoverIDVariables
>(SET_ALBUM_COVER_ID_MUTATION, {
const [resetAlbumCover, { loading }] = useMutation<
resetAlbumCover,
resetAlbumCoverVariables
>(RESET_ALBUM_COVER_MUTATION, {
variables: {
albumID: id,
coverID: '-1',
},
})
@ -102,10 +108,9 @@ export const SidebarAlbumCover = ({ id }: SidebarAlbumCoverProps) => {
className="text-red-500 font-bold uppercase text-xs"
disabled={loading}
onClick={() => {
setAlbumCoverID({
resetAlbumCover({
variables: {
albumID: id,
coverID: '-1',
},
})
}}

View File

@ -1,7 +1,6 @@
import React from 'react'
import { useQuery, gql } from '@apollo/client'
import { SidebarAlbumShare } from './Sharing'
import { SidebarAlbumCover } from './AlbumCovers'
import { useTranslation } from 'react-i18next'
import SidebarHeader from './SidebarHeader'
import {
@ -47,10 +46,6 @@ const AlbumSidebar = ({ albumId }: AlbumSidebarProps) => {
{/* <h1 className="text-3xl font-semibold">{data.album.title}</h1> */}
<SidebarAlbumShare id={albumId} />
</div>
<div className="mt-8">
{/* <h1 className="text-3xl font-semibold">{data.album.title}</h1> */}
<SidebarAlbumCover id={albumId} />
</div>
</div>
)
}

View File

@ -26,7 +26,6 @@ import {
import { sidebarDownloadQuery_media_downloads } from './__generated__/sidebarDownloadQuery'
import SidebarHeader from './SidebarHeader'
import { SidebarPhotoCover } from './AlbumCovers'
const SIDEBAR_MEDIA_QUERY = gql`
query sidebarPhoto($id: ID!) {
@ -366,9 +365,6 @@ const SidebarContent = ({ media, hidePreview }: SidebarContentProps) => {
<MetadataInfo media={media} />
<SidebarDownload media={media} />
<SidebarPhotoShare id={media.id} />
<div className="mt-8">
<SidebarPhotoCover id={'3'} cover_id={media.id} />
</div>
</div>
)
}

View File

@ -34,6 +34,8 @@ import {
import { authToken } from '../../helpers/authentication'
import { SidebarSection, SidebarSectionTitle } from './SidebarComponents'
import { SidebarPhotoCover, SidebarAlbumCover } from './AlbumCovers'
import { ReactComponent as LinkIcon } from './icons/shareLinkIcon.svg'
import { ReactComponent as CopyIcon } from './icons/shareCopyIcon.svg'
import { ReactComponent as DeleteIcon } from './icons/shareDeleteIcon.svg'
@ -312,10 +314,9 @@ export const SidebarPhotoShare = ({ id }: SidebarSharePhotoProps) => {
const [
loadShares,
{ loading: queryLoading, error: sharesError, data: sharesData },
] =
useLazyQuery<sidebarGetPhotoShares, sidebarGetPhotoSharesVariables>(
SHARE_PHOTO_QUERY
)
] = useLazyQuery<sidebarGetPhotoShares, sidebarGetPhotoSharesVariables>(
SHARE_PHOTO_QUERY
)
const [sharePhoto, { loading: mutationLoading }] = useMutation<
sidebarPhotoAddShare,
@ -432,36 +433,54 @@ const SidebarShare = ({
)
}
return (
<SidebarSection>
<SidebarSectionTitle>
{t('sidebar.sharing.title', 'Sharing options')}
</SidebarSectionTitle>
<div>
<table className="border-collapse w-full">
<tbody>{optionsRows}</tbody>
<tfoot>
<tr className="text-left border-gray-100 border-b border-t">
<td colSpan={2} className="pl-4 py-2">
<button
className="text-green-500 font-bold uppercase text-xs"
disabled={loading}
onClick={() => {
shareItem({
variables: {
id,
},
})
}}
>
<AddIcon className="inline-block mr-2" />
<span>{t('sidebar.sharing.add_share', 'Add shares')}</span>
</button>
</td>
</tr>
</tfoot>
</table>
let coverPhotoSection
if (isPhoto) {
coverPhotoSection = (
<div className="mt-8">
<SidebarPhotoCover cover_id={id} />
</div>
</SidebarSection>
)
} else {
coverPhotoSection = (
<div className="mt-8">
<SidebarAlbumCover id={id} />
</div>
)
}
return (
<div>
<SidebarSection>
<SidebarSectionTitle>
{t('sidebar.sharing.title', 'Sharing options')}
</SidebarSectionTitle>
<div>
<table className="border-collapse w-full">
<tbody>{optionsRows}</tbody>
<tfoot>
<tr className="text-left border-gray-100 border-b border-t">
<td colSpan={2} className="pl-4 py-2">
<button
className="text-green-500 font-bold uppercase text-xs"
disabled={loading}
onClick={() => {
shareItem({
variables: {
id,
},
})
}}
>
<AddIcon className="inline-block mr-2" />
<span>{t('sidebar.sharing.add_share', 'Add shares')}</span>
</button>
</td>
</tr>
</tfoot>
</table>
</div>
</SidebarSection>
{coverPhotoSection}
</div>
)
}

View File

@ -0,0 +1,24 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL mutation operation: resetAlbumCover
// ====================================================
export interface resetAlbumCover_resetAlbumCover {
__typename: 'Album'
id: string
}
export interface resetAlbumCover {
/**
* Reset the assigned cover image for an album
*/
resetAlbumCover: resetAlbumCover_resetAlbumCover
}
export interface resetAlbumCoverVariables {
albumID: string
}

View File

@ -0,0 +1,24 @@
/* tslint:disable */
/* eslint-disable */
// @generated
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL mutation operation: setAlbumCover
// ====================================================
export interface setAlbumCover_setAlbumCover {
__typename: 'Album'
coverID: number
}
export interface setAlbumCover {
/**
* Assign a cover image to an album
*/
setAlbumCover: setAlbumCover_setAlbumCover
}
export interface setAlbumCoverVariables {
coverID: string
}