stash
This commit is contained in:
parent
4671860fa4
commit
18a3e40435
7 changed files with 43 additions and 11 deletions
|
|
@ -28,8 +28,8 @@ def _accessible_files(request):
|
||||||
# friends-or-self with whatever references it (item, profile picture), a member of the group
|
# friends-or-self with whatever references it (item, profile picture), a member of the group
|
||||||
# that owns the item it's attached to, or it's their own staged photo.
|
# that owns the item it's attached to, or it's their own staged photo.
|
||||||
return File.objects.filter(
|
return File.objects.filter(
|
||||||
Q(connected_items__owner__in=request.user.friends_or_self()) |
|
Q(connected_items__owner__in=request.user.friends_or_self(), connected_items__is_deleted=False) |
|
||||||
Q(connected_items__owner_group__in=request.user.member_of_groups.all()) |
|
Q(connected_items__owner_group__in=request.user.member_of_groups.all(), connected_items__is_deleted=False) |
|
||||||
Q(profile_picture_users__in=request.user.friends_or_self()) |
|
Q(profile_picture_users__in=request.user.friends_or_self()) |
|
||||||
Q(staged_by_workflows__owner__in=request.user.user.all())
|
Q(staged_by_workflows__owner__in=request.user.user.all())
|
||||||
).distinct()
|
).distinct()
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,16 @@ class MediaUrlTestCase(FilesTestMixin, UserTestMixin, InventoryTestMixin, Toolsh
|
||||||
self.assertEqual(reply.status_code, 404)
|
self.assertEqual(reply.status_code, 404)
|
||||||
self.assertTrue('X-Accel-Redirect' not in reply.headers)
|
self.assertTrue('X-Accel-Redirect' not in reply.headers)
|
||||||
|
|
||||||
|
def test_file_url_only_connected_via_deleted_item(self):
|
||||||
|
# test_file2 is only reachable through item1; soft-deleting it doesn't sever the files
|
||||||
|
# M2M row, so this would regress to serving test_file2 as if item1 were still live if
|
||||||
|
# _accessible_files ever stops excluding soft-deleted items again.
|
||||||
|
self.f['item1'].delete()
|
||||||
|
reply = client.get(
|
||||||
|
f"/media/{self.f['hash2'][:2]}/{self.f['hash2'][2:4]}/{self.f['hash2'][4:6]}/{self.f['hash2'][6:]}",
|
||||||
|
self.f['local_user1'])
|
||||||
|
self.assertEqual(reply.status_code, 404)
|
||||||
|
|
||||||
@override_settings(SERVE_X_ACCEL_REDIRECT=True)
|
@override_settings(SERVE_X_ACCEL_REDIRECT=True)
|
||||||
def test_profile_picture_url(self):
|
def test_profile_picture_url(self):
|
||||||
self.f['local_user1'].profile_picture = self.f['test_file3']
|
self.f['local_user1'].profile_picture = self.f['test_file3']
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ def list_all_files(request, format=None):
|
||||||
# request.user is a ToolshedUser here; reach group membership via public_identity.
|
# request.user is a ToolshedUser here; reach group membership via public_identity.
|
||||||
files = File.objects.select_related().filter(
|
files = File.objects.select_related().filter(
|
||||||
Q(connected_items__owner=request.user) |
|
Q(connected_items__owner=request.user) |
|
||||||
Q(connected_items__owner_group__in=request.user.public_identity.member_of_groups.all())
|
Q(connected_items__owner_group__in=request.user.public_identity.member_of_groups.all()),
|
||||||
|
connected_items__is_deleted=False
|
||||||
).distinct()
|
).distinct()
|
||||||
return Response(FileSerializer(files, many=True).data)
|
return Response(FileSerializer(files, many=True).data)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,17 @@ class FileApiTestCase(UserTestMixin, FilesTestMixin, InventoryTestMixin, Toolshe
|
||||||
self.assertEqual(response.json()[1]['name'],
|
self.assertEqual(response.json()[1]['name'],
|
||||||
f"/media/{self.f['hash2'][:2]}/{self.f['hash2'][2:4]}/{self.f['hash2'][4:6]}/{self.f['hash2'][6:]}")
|
f"/media/{self.f['hash2'][:2]}/{self.f['hash2'][2:4]}/{self.f['hash2'][4:6]}/{self.f['hash2'][6:]}")
|
||||||
|
|
||||||
|
def test_list_all_files_excludes_files_only_connected_via_deleted_item(self):
|
||||||
|
# test_file2 is only reachable through item1; test_file1 is also reachable through item2,
|
||||||
|
# which stays live. Soft-deleting item1 doesn't sever its files M2M rows, so this would
|
||||||
|
# regress to listing test_file2 as if it were still owned if the join-based filter ever
|
||||||
|
# stops excluding soft-deleted items again.
|
||||||
|
self.f['item1'].delete()
|
||||||
|
response = client.get(f"/api/v1/files/", self.f['local_user1'])
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
hashes = [f['hash'] for f in response.json()]
|
||||||
|
self.assertEqual(hashes, [self.f['hash1']])
|
||||||
|
|
||||||
def test_files(self):
|
def test_files(self):
|
||||||
response = client.get(f"/api/v1/item_files/{self.f['item1'].id}/", self.f['local_user1'])
|
response = client.get(f"/api/v1/item_files/{self.f['item1'].id}/", self.f['local_user1'])
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export default {
|
||||||
},
|
},
|
||||||
fallbackSrc: {
|
fallbackSrc: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '/assets/img/avatars/avatar.png'
|
default: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+CjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjEyIiBmaWxsPSIjY2VkNGRhIi8+CjxjaXJjbGUgY3g9IjEyIiBjeT0iOS41IiByPSI0IiBmaWxsPSIjZmZmZmZmIi8+CjxwYXRoIGQ9Ik00IDIwLjJDNCAxNi4yIDcuNiAxMy41IDEyIDEzLjVzOCAyLjcgOCA2Ljd2MC4zSDR2LTAuM3oiIGZpbGw9IiNmZmZmZmYiLz4KPC9zdmc+Cg=='
|
||||||
},
|
},
|
||||||
width: {
|
width: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
totalSteps() {
|
totalSteps() {
|
||||||
return this.stepDefinitions.length || this.workflowInstance?.total_steps || 1;
|
return this.stepDefinitions.length || 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
currentStepDefinition() {
|
currentStepDefinition() {
|
||||||
|
|
@ -314,6 +314,7 @@ export default {
|
||||||
...mapActions([
|
...mapActions([
|
||||||
'fetchActiveWorkflows',
|
'fetchActiveWorkflows',
|
||||||
'updateWorkflow',
|
'updateWorkflow',
|
||||||
|
'updateWorkflowStep',
|
||||||
'deleteWorkflow'
|
'deleteWorkflow'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
|
@ -338,11 +339,20 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
navigateToStep(step) {
|
async navigateToStep(step) {
|
||||||
const stepStr = String(step);
|
const stepStr = String(step);
|
||||||
// For navigation, we need to validate the step exists in step definitions
|
// For navigation, we need to validate the step exists in step definitions
|
||||||
const stepExists = this.stepDefinitions.some(step => step.step === stepStr);
|
const stepExists = this.stepDefinitions.some(step => step.step === stepStr);
|
||||||
if (stepExists || (step >= 1 && step <= this.totalSteps)) {
|
if (stepExists || (step >= 1 && step <= this.totalSteps)) {
|
||||||
|
try {
|
||||||
|
await this.updateWorkflowStep({
|
||||||
|
workflowId: this.id,
|
||||||
|
currentStep: stepStr,
|
||||||
|
payload: this.workflowInstance.payload
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error persisting workflow step:', error);
|
||||||
|
}
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: 'workflow-detail',
|
name: 'workflow-detail',
|
||||||
params: { id: this.id, step: stepStr }
|
params: { id: this.id, step: stepStr }
|
||||||
|
|
|
||||||
|
|
@ -248,11 +248,11 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async viewWorkflowDetails(workflow) {
|
async viewWorkflowDetails(workflow) {
|
||||||
console.log('Viewing details for workflow:', workflow);
|
const currentStep = String(
|
||||||
const currentStep = workflow.current_step ||
|
workflow.current_step ||
|
||||||
workflow.payload?.current_step ||
|
getWorkflow(workflow.slug)?.stepDefinitions?.[0]?.step ||
|
||||||
getWorkflow(workflow.name)?.stepDefinitions?.[0]?.step ||
|
1
|
||||||
"initial";
|
);
|
||||||
|
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: 'workflow-detail',
|
name: 'workflow-detail',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue