Skip to content

Commit

Permalink
it works!
Browse files Browse the repository at this point in the history
  • Loading branch information
ciur committed Oct 23, 2024
1 parent 5c45209 commit 1e94165
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 15 deletions.
3 changes: 3 additions & 0 deletions docker/cloud/etc/logging.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ loggers:
i3worker:
level: INFO
handlers: [console]
papermerge.core.features.router:
level: DEBUG
handlers: [ console ]
path_tmpl_worker:
level: DEBUG
handlers: [ console ]
Expand Down
9 changes: 6 additions & 3 deletions papermerge/core/features/document_types/db/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ def delete_document_type(session: Session, document_type_id: uuid.UUID):


def update_document_type(
session: Session, document_type_id: uuid.UUID, attrs: schemas.UpdateDocumentType
session: Session,
document_type_id: uuid.UUID,
attrs: schemas.UpdateDocumentType,
user_id: uuid.UUID,
) -> schemas.DocumentType:
stmt = select(DocumentType).where(DocumentType.id == document_type_id)
doc_type = session.execute(stmt).scalars().one()
Expand All @@ -89,7 +92,6 @@ def update_document_type(
doc_type.custom_fields = custom_fields

notify_path_tmpl_worker = False

if doc_type.path_template != attrs.path_template:
doc_type.path_template = attrs.path_template
notify_path_tmpl_worker = True
Expand All @@ -104,7 +106,7 @@ def update_document_type(
# to new target path based on path template evaluation
send_task(
const.PATH_TMPL_MOVE_DOCUMENTS,
kwargs={"document_type_id": str(document_type_id)},
kwargs={"document_type_id": str(document_type_id), "user_id": str(user_id)},
route_name="path_tmpl",
)

Expand All @@ -113,4 +115,5 @@ def update_document_type(

@skip_in_tests
def send_task(*args, **kwargs):
logger.debug(f"Send task {args} {kwargs}")
celery_app.send_task(*args, **kwargs)
5 changes: 4 additions & 1 deletion papermerge/core/features/document_types/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,10 @@ def update_document_type(
"""
try:
dtype: schemas.DocumentType = db.update_document_type(
db_session, document_type_id=document_type_id, attrs=attrs
db_session,
document_type_id=document_type_id,
attrs=attrs,
user_id=cur_user.id,
)
except NoResultFound:
raise HTTPException(status_code=404, detail="Document type not found")
Expand Down
2 changes: 1 addition & 1 deletion papermerge/core/routers/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def update_document_custom_field_values(

celery_app.send_task(
const.PATH_TMPL_MOVE_DOCUMENT,
kwargs={"document_id": str(document_id)},
kwargs={"document_id": str(document_id), "user_id": str(user.id)},
route_name="path_tmpl",
)

Expand Down
80 changes: 77 additions & 3 deletions ui2/src/features/document/apiSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,29 @@ import {
PAGINATION_DEFAULT_ITEMS_PER_PAGES
} from "@/cconstants"
import {apiSlice} from "@/features/api/slice"
import type {DocumentCFV, Paginated} from "@/types"
import type {
DocumentCFV,
Paginated,
ServerNotifDocumentMoved,
ServerNotifPayload,
ServerNotifType
} from "@/types"
import {
CFV,
DocumentType,
ExtractStrategyType,
OrderType,
TransferStrategyType
} from "@/types"
import {getBaseURL, getDefaultHeaders, imageEncode} from "@/utils"
import {
getBaseURL,
getDefaultHeaders,
getRemoteUserID,
getWSURL,
imageEncode
} from "@/utils"

import {documentMovedNotifReceived} from "./documentVersSlice"

type ShortPageType = {
number: number
Expand Down Expand Up @@ -83,7 +97,67 @@ export const apiSliceWithDocuments = apiSlice.injectEndpoints({
endpoints: builder => ({
getDocument: builder.query<DocumentType, string>({
query: nodeID => `/documents/${nodeID}`,
providesTags: (_result, _error, arg) => [{type: "Document", id: arg}]
providesTags: (_result, _error, arg) => [{type: "Document", id: arg}],
async onCacheEntryAdded(arg, lifecycleApi) {
let url = getWSURL()

if (!url) {
return
}

if (getRemoteUserID()) {
url = `${url}?remote-user-id=${getRemoteUserID()}`
}
const ws = new WebSocket(url)
try {
// wait for the initial query to resolve before proceeding
await lifecycleApi.cacheDataLoaded

// when data is received from the socket connection to the server,
// update our query result with the received message
const listener = (event: MessageEvent<string>) => {
const message: {
type: ServerNotifType
payload: ServerNotifPayload
} = JSON.parse(event.data)
console.log(`${message.type} received`)
console.log(message.payload)
switch (message.type) {
case "document_moved": {
const payload = message.payload as ServerNotifDocumentMoved
console.log(`Invalidating Document ${payload.document_id}`)
lifecycleApi.dispatch(
apiSlice.util.invalidateTags([
{
type: "Document",
id: payload.document_id
},
{
type: "Node",
id: payload.source_folder_id
},
{
type: "Node",
id: payload.target_folder_id
}
])
)
lifecycleApi.dispatch(documentMovedNotifReceived(payload))
break
}
default:
break
}
}
ws.addEventListener("message", listener)
} catch {
// no-op in case `cacheEntryRemoved` resolves before `cacheDataLoaded`,
// in which case `cacheDataLoaded` will throw
}
await lifecycleApi.cacheEntryRemoved
// perform cleanup steps once the `cacheEntryRemoved` promise resolves
ws.close()
}
}),
getPageImage: builder.query<string, string>({
//@ts-ignore
Expand Down
22 changes: 19 additions & 3 deletions ui2/src/features/document/documentVersSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import type {
ClientDocumentVersion,
ClientPage,
DocumentType,
DroppedThumbnailPosition
DroppedThumbnailPosition,
ServerNotifDocumentMoved
} from "@/types"
import {PanelMode} from "@/types"
import {contains_every, reorder} from "@/utils"
import {notifications} from "@mantine/notifications"
import {
PayloadAction,
createEntityAdapter,
Expand Down Expand Up @@ -102,6 +104,15 @@ const docVersSlice = createSlice({
}
})
state.entities[targetDocVerID].pages = newPages
},
documentMovedNotifReceived(
state,
action: PayloadAction<ServerNotifDocumentMoved>
) {
notifications.show({
withBorder: true,
message: `Document title updated to ${action.payload.new_document_title}`
})
}
},
extraReducers(builder) {
Expand Down Expand Up @@ -134,8 +145,13 @@ const docVersSlice = createSlice({
}
})

export const {pagesDroppedInDoc, pagesRotated, pagesReseted, pagesDeleted} =
docVersSlice.actions
export const {
pagesDroppedInDoc,
pagesRotated,
pagesReseted,
pagesDeleted,
documentMovedNotifReceived
} = docVersSlice.actions
export default docVersSlice.reducer

export const {
Expand Down
84 changes: 82 additions & 2 deletions ui2/src/features/nodes/apiSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,24 @@ import type {
FolderType,
NodeType,
Paginated,
ServerNotifDocumentMoved,
ServerNotifDocumentsMoved,
ServerNotifPayload,
ServerNotifType,
SortMenuColumn,
SortMenuDirection
} from "@/types"
import {getBaseURL, getDefaultHeaders, imageEncode} from "@/utils"
import {
getBaseURL,
getDefaultHeaders,
getRemoteUserID,
getWSURL,
imageEncode
} from "@/utils"
import {
documentMovedNotifReceived,
documentsMovedNotifReceived
} from "./nodesSlice"

type CreateFolderType = {
title: string
Expand Down Expand Up @@ -77,7 +91,73 @@ export const apiSliceWithNodes = apiSlice.injectEndpoints({
}),
getFolder: builder.query<FolderType, string>({
query: folderID => `/folders/${folderID}`,
providesTags: (_result, _error, arg) => [{type: "Folder", id: arg}]
providesTags: (_result, _error, arg) => [{type: "Folder", id: arg}],
async onCacheEntryAdded(arg, lifecycleApi) {
let url = getWSURL()

if (!url) {
return
}

if (getRemoteUserID()) {
url = `${url}?remote-user-id=${getRemoteUserID()}`
}
const ws = new WebSocket(url)
try {
// wait for the initial query to resolve before proceeding
await lifecycleApi.cacheDataLoaded

// when data is received from the socket connection to the server,
// update our query result with the received message
const listener = (event: MessageEvent<string>) => {
const message: {
type: ServerNotifType
payload: ServerNotifPayload
} = JSON.parse(event.data)

switch (message.type) {
case "documents_moved": {
const payload = message.payload as ServerNotifDocumentsMoved
let invSourceFolderTags = payload.source_folder_ids.map(i => {
return {type: "Folder" as const, id: i}
})
let invTargetFolderTags = payload.target_folder_ids.map(i => {
return {type: "Folder" as const, id: i}
})
const invTags = invTargetFolderTags.concat(invSourceFolderTags)
lifecycleApi.dispatch(apiSlice.util.invalidateTags(invTags))
lifecycleApi.dispatch(documentsMovedNotifReceived(payload))
break
}
case "document_moved": {
const payload = message.payload as ServerNotifDocumentMoved

if (
arg == payload.source_folder_id ||
arg == payload.target_folder_id
) {
lifecycleApi.dispatch(
apiSlice.util.invalidateTags([{type: "Folder", id: arg}])
)
lifecycleApi.dispatch(documentMovedNotifReceived(payload))
}

break
}

default:
break
}
}
ws.addEventListener("message", listener)
} catch {
// no-op in case `cacheEntryRemoved` resolves before `cacheDataLoaded`,
// in which case `cacheDataLoaded` will throw
}
await lifecycleApi.cacheEntryRemoved
// perform cleanup steps once the `cacheEntryRemoved` promise resolves
ws.close()
}
}),
getDocumentThumbnail: builder.query<string, string>({
//@ts-ignore
Expand Down
36 changes: 34 additions & 2 deletions ui2/src/features/nodes/nodesSlice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import {AppStartListening} from "@/app/listenerMiddleware"
import {RootState} from "@/app/types"
import {apiSliceWithSearch} from "@/features/search/apiSlice"
import type {NodeType, Paginated, ServerErrorType} from "@/types"
import type {
NodeType,
Paginated,
ServerErrorType,
ServerNotifDocumentMoved,
ServerNotifDocumentsMoved
} from "@/types"
import {notifications} from "@mantine/notifications"
import {
PayloadAction,
Expand All @@ -17,7 +23,30 @@ const initialState = nodeAdapter.getInitialState()
const nodesSlice = createSlice({
name: "nodes",
initialState,
reducers: {},
reducers: {
documentsMovedNotifReceived: (
state,
action: PayloadAction<ServerNotifDocumentsMoved>
) => {
const payload = action.payload

notifications.show({
withBorder: true,
message: `${payload.count} were documents path was updated based on new ${payload.document_type_name} path template`
})
},
documentMovedNotifReceived: (
state,
action: PayloadAction<ServerNotifDocumentMoved>
) => {
const payload = action.payload

notifications.show({
withBorder: true,
message: `Document ${payload.new_document_title} moved to new folder (based on custom field changes)`
})
}
},
extraReducers(builder) {
builder.addMatcher(
apiSliceWithNodes.endpoints.getPaginatedNodes.matchFulfilled,
Expand All @@ -43,6 +72,9 @@ const nodesSlice = createSlice({
}
})

export const {documentsMovedNotifReceived, documentMovedNotifReceived} =
nodesSlice.actions

export default nodesSlice.reducer

export const selectFoldersResult = (folderID: string) =>
Expand Down
Loading

0 comments on commit 1e94165

Please sign in to comment.