@@ -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