Skip to content

Commit 4891b3b

Browse files
authored
Merge pull request #563 from dbarzin/dev
Implement document deduplication based on SHA-256 hash
2 parents 5643ac7 + 88d0c2e commit 4891b3b

File tree

1 file changed

+36
-8
lines changed

1 file changed

+36
-8
lines changed

app/Http/Controllers/DocumentController.php

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public function get(int $id)
124124
public function store(Request $request)
125125
{
126126
// Not for API
127-
abort_if((Auth::User()->role === 4), Response::HTTP_FORBIDDEN, '403 Forbidden');
127+
abort_if((Auth::User()->isAPI()), Response::HTTP_FORBIDDEN, '403 Forbidden');
128128

129129
// Get file
130130
$file = $request->file('file');
@@ -135,11 +135,11 @@ public function store(Request $request)
135135
// Auditee may save document to assigned control only
136136
abort_if(
137137
Auth::User()->role === 5 &&
138-
! (DB::table('control_user')
138+
! (DB::table('control_user')
139139
->where('control_id', $control_id)
140140
->where('user_id', Auth::User()->id)
141141
->exists()
142-
||
142+
||
143143
DB::table('control_user_group')
144144
->join('user_user_group', 'control_user_group.user_group_id', '=', 'user_user_group.user_group_id')
145145
->where('control_user_group.control_id', $control_id)
@@ -149,22 +149,50 @@ public function store(Request $request)
149149
'403 Forbidden'
150150
);
151151

152-
// Save document
152+
// Calculate file hash
153+
$hash = hash_file('sha256', $file->path());
154+
155+
// Check if a document with this hash already exists
156+
$existingDocument = Document::where('hash', $hash)->first();
157+
158+
// Create new document record
153159
$doc = new Document();
154160
$doc->control_id = $control_id;
155161
$doc->filename = $file->getClientOriginalName();
156162
$doc->mimetype = $file->getClientMimeType();
157163
$doc->size = $file->getSize();
158-
$doc->hash = hash_file('sha256', $file->path());
164+
$doc->hash = $hash;
159165
$doc->save();
160166

161-
// Move file to storage folder
162-
$file->move(storage_path('docs'), (string) $doc->id);
167+
$newPath = storage_path('docs/' . $doc->id);
168+
169+
$deduplicated = false;
170+
if ($existingDocument !== null) {
171+
// Reuse existing file - create hard link
172+
$existingPath = storage_path('docs/' . $existingDocument->id);
173+
174+
if (file_exists($existingPath)) {
175+
if (link($existingPath, $newPath)) {
176+
$deduplicated = true;
177+
} else {
178+
// Fallback: hard-link failed (e.g., different filesystem)
179+
$file->move(storage_path('docs'), (string) $doc->id);
180+
}
181+
} else {
182+
// Fallback: if existing file is missing, store the uploaded file
183+
$file->move(storage_path('docs'), (string) $doc->id);
184+
}
185+
} else {
186+
// New file - store it
187+
$file->move(storage_path('docs'), (string) $doc->id);
188+
}
163189

164190
// response
165191
return response()->json(
166-
['success' => $doc->filename,
192+
[
193+
'success' => $doc->filename,
167194
'id' => $doc->id,
195+
'deduplicated' => $deduplicated,
168196
]
169197
);
170198
}

0 commit comments

Comments
 (0)