<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://ohcnwiki.tellmey.fyi/index.php?action=history&amp;feed=atom&amp;title=References%2FFile_Upload</id>
	<title>References/File Upload - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://ohcnwiki.tellmey.fyi/index.php?action=history&amp;feed=atom&amp;title=References%2FFile_Upload"/>
	<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=References/File_Upload&amp;action=history"/>
	<updated>2026-07-06T07:11:34Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.4</generator>
	<entry>
		<id>https://ohcnwiki.tellmey.fyi/index.php?title=References/File_Upload&amp;diff=469&amp;oldid=prev</id>
		<title>Admin: Add Navbox platform (via update-page on MediaWiki MCP Server)</title>
		<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=References/File_Upload&amp;diff=469&amp;oldid=prev"/>
		<updated>2026-07-06T04:23:01Z</updated>

		<summary type="html">&lt;p&gt;Add Navbox platform (via update-page on MediaWiki MCP Server)&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 09:53, 6 July 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 313:&lt;/td&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 313:&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* Archival (&amp;lt;code&amp;gt;POST .../{external_id}/archive/&amp;lt;/code&amp;gt;, body &amp;lt;code&amp;gt;{ archive_reason }&amp;lt;/code&amp;gt;) sets &amp;lt;code&amp;gt;is_archived&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archive_reason&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archived_datetime&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archived_by&amp;lt;/code&amp;gt; server-side and returns &amp;lt;code&amp;gt;FileUploadListSpec&amp;lt;/code&amp;gt;. This soft state is separate from the &amp;lt;code&amp;gt;EMRBaseModel&amp;lt;/code&amp;gt; soft-delete (&amp;lt;code&amp;gt;deleted&amp;lt;/code&amp;gt;).&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* Archival (&amp;lt;code&amp;gt;POST .../{external_id}/archive/&amp;lt;/code&amp;gt;, body &amp;lt;code&amp;gt;{ archive_reason }&amp;lt;/code&amp;gt;) sets &amp;lt;code&amp;gt;is_archived&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archive_reason&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archived_datetime&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archived_by&amp;lt;/code&amp;gt; server-side and returns &amp;lt;code&amp;gt;FileUploadListSpec&amp;lt;/code&amp;gt;. This soft state is separate from the &amp;lt;code&amp;gt;EMRBaseModel&amp;lt;/code&amp;gt; soft-delete (&amp;lt;code&amp;gt;deleted&amp;lt;/code&amp;gt;).&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* &amp;lt;code&amp;gt;mark_upload_completed&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;archive&amp;lt;/code&amp;gt; both return &amp;lt;code&amp;gt;FileUploadListSpec&amp;lt;/code&amp;gt; (no signed URL).&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;* &amp;lt;code&amp;gt;mark_upload_completed&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;archive&amp;lt;/code&amp;gt; both return &amp;lt;code&amp;gt;FileUploadListSpec&amp;lt;/code&amp;gt; (no signed URL).&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-empty diff-side-deleted&quot;&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td colspan=&quot;2&quot; class=&quot;diff-empty diff-side-deleted&quot;&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Navbox platform}}&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Related}}&lt;/div&gt;&lt;/td&gt;
  &lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;
  &lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Related}}&lt;/div&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;!-- diff cache key mediawiki:diff:1.41:old-168:rev-469:wikidiff2=table:1.14.2:bc2a06be --&gt;
&lt;/table&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://ohcnwiki.tellmey.fyi/index.php?title=References/File_Upload&amp;diff=168&amp;oldid=prev</id>
		<title>Admin: OHC identity seed</title>
		<link rel="alternate" type="text/html" href="https://ohcnwiki.tellmey.fyi/index.php?title=References/File_Upload&amp;diff=168&amp;oldid=prev"/>
		<updated>2026-07-04T22:45:30Z</updated>

		<summary type="html">&lt;p&gt;OHC identity seed&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Doc header&lt;br /&gt;
|type=reference&lt;br /&gt;
|domain=platform&lt;br /&gt;
|title=File Upload&lt;br /&gt;
|order=1&lt;br /&gt;
|introduced=3.0&lt;br /&gt;
|model=FileUpload&lt;br /&gt;
|reference=References/User &amp;amp;amp; Skills&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;code&amp;gt;FileUpload&amp;lt;/code&amp;gt; is the metadata record for a file living in S3-compatible object storage. You touch it whenever a Care resource needs an attachment — a patient document, an X-ray on an encounter, a signed consent form.&lt;br /&gt;
&lt;br /&gt;
Two layers split the work. The Django model is storage: it persists the row and an opaque &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; JSON column, nothing more. The Pydantic resource specs in &amp;lt;code&amp;gt;care/emr/resources/file_upload/spec.py&amp;lt;/code&amp;gt; are the API — they define the &amp;lt;code&amp;gt;file_type&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;file_category&amp;lt;/code&amp;gt; enums, validate the upload, decide what goes into &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;mime_type&amp;lt;/code&amp;gt;), and shape every read/write payload, including &amp;lt;code&amp;gt;extension&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;signed_url&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;read_signed_url&amp;lt;/code&amp;gt;, which are computed on the fly and have no backing columns.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Source:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
* Model: [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/models/file_upload.py &amp;lt;code&amp;gt;care/emr/models/file_upload.py&amp;lt;/code&amp;gt;]&lt;br /&gt;
* Specs: [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/resources/file_upload/spec.py &amp;lt;code&amp;gt;care/emr/resources/file_upload/spec.py&amp;lt;/code&amp;gt;]&lt;br /&gt;
* Viewset: [&amp;lt;nowiki/&amp;gt;https://github.com/ohcnetwork/care/blob/develop/care/emr/api/viewsets/file_upload.py &amp;lt;code&amp;gt;care/emr/api/viewsets/file_upload.py&amp;lt;/code&amp;gt;]&lt;br /&gt;
&lt;br /&gt;
== Models ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Model&lt;br /&gt;
! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FileUpload&amp;lt;/code&amp;gt;&lt;br /&gt;
| Metadata record for a file stored in object storage (S3), associated with another Care resource by &amp;lt;code&amp;gt;file_type&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;associating_id&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FileUpload&amp;lt;/code&amp;gt; extends [[References/Base models &amp;amp;amp; conventions|&amp;lt;code&amp;gt;EMRBaseModel&amp;lt;/code&amp;gt;]] (shared Care EMR base with &amp;lt;code&amp;gt;external_id&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; JSON, audit fields, and soft-delete semantics).&lt;br /&gt;
&lt;br /&gt;
== &amp;lt;code&amp;gt;FileUpload&amp;lt;/code&amp;gt; fields ==&lt;br /&gt;
&lt;br /&gt;
=== File metadata ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=FileUpload|section=File metadata|name=name|type=CharField(2000)|notes=User-facing file name. Required on the API (&amp;lt;code&amp;gt;FileUploadBaseSpec.name&amp;lt;/code&amp;gt;)}}&lt;br /&gt;
{{Field|model=FileUpload|section=File metadata|name=internal_name|type=CharField(2000)|notes=Storage object key. Set server-side from &amp;lt;code&amp;gt;original_name&amp;lt;/code&amp;gt; on create, then a random key is generated on &amp;lt;code&amp;gt;save()&amp;lt;/code&amp;gt;. Never set by clients}}&lt;br /&gt;
{{Field|model=FileUpload|section=File metadata|name=associating_id|type=CharField(100)|notes=The &amp;lt;code&amp;gt;external_id&amp;lt;/code&amp;gt; of the owning resource. Required (&amp;lt;code&amp;gt;blank=False, null=False&amp;lt;/code&amp;gt;). There&amp;#039;s no DB &amp;lt;code&amp;gt;ForeignKey&amp;lt;/code&amp;gt; — integrity is enforced in the app layer}}&lt;br /&gt;
{{Field|model=FileUpload|section=File metadata|name=file_type|type=CharField(100)|notes=Domain of the owning resource. API-constrained to [[#filetypechoices-values}}&lt;br /&gt;
{{Field|model=FileUpload|section=File metadata|name=file_category|type=CharField(100)|notes=API-constrained to [[#filecategorychoices-values}}&lt;br /&gt;
{{Field|model=FileUpload|section=File metadata|name=upload_completed|type=BooleanField|notes=Default &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;. Flips to &amp;lt;code&amp;gt;True&amp;lt;/code&amp;gt; once the client finishes the direct-to-S3 upload — or immediately, on the inline &amp;lt;code&amp;gt;upload-file&amp;lt;/code&amp;gt; path}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; JSON contents ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; is the opaque &amp;lt;code&amp;gt;JSONField&amp;lt;/code&amp;gt; inherited from &amp;lt;code&amp;gt;EMRBaseModel&amp;lt;/code&amp;gt;. The specs put exactly one structured key in it:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key&lt;br /&gt;
! Type&lt;br /&gt;
! Shape / Notes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mime_type&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;&lt;br /&gt;
| MIME type of the file. Written in &amp;lt;code&amp;gt;FileUploadCreateSpec.perform_extra_deserialization&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;obj.meta[&amp;amp;quot;mime_type&amp;amp;quot;] = self.mime_type&amp;lt;/code&amp;gt;); read back during serialization via &amp;lt;code&amp;gt;obj.meta.get(&amp;amp;quot;mime_type&amp;amp;quot;)&amp;lt;/code&amp;gt;. Validated against &amp;lt;code&amp;gt;settings.ALLOWED_MIME_TYPES&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Archival ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Notes&lt;br /&gt;
{{Field|model=FileUpload|section=Archival|name=is_archived|type=BooleanField|notes=Default &amp;lt;code&amp;gt;False&amp;lt;/code&amp;gt;}}&lt;br /&gt;
{{Field|model=FileUpload|section=Archival|name=archive_reason|type=TextField|notes=Blank-able; set when archiving (required in the &amp;lt;code&amp;gt;archive&amp;lt;/code&amp;gt; action body)}}&lt;br /&gt;
{{Field|model=FileUpload|section=Archival|name=archived_datetime|type=DateTimeField|notes=Nullable; set to &amp;lt;code&amp;gt;timezone.now()&amp;lt;/code&amp;gt; when archived}}&lt;br /&gt;
{{Field|model=FileUpload|section=Archival|name=archived_by|type=FK → User (PROTECT)|notes=Nullable; &amp;lt;code&amp;gt;related_name=&amp;amp;quot;archived_files&amp;amp;quot;&amp;lt;/code&amp;gt;}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Storage manager ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FileUpload&amp;lt;/code&amp;gt; declares a class-level &amp;lt;code&amp;gt;files_manager = S3FilesManager(BucketType.PATIENT)&amp;lt;/code&amp;gt;. It&amp;#039;s not a database field — it&amp;#039;s the object-storage helper that mints signed write/read URLs and runs &amp;lt;code&amp;gt;put_object&amp;lt;/code&amp;gt;, all against the &amp;lt;code&amp;gt;PATIENT&amp;lt;/code&amp;gt; bucket.&lt;br /&gt;
&lt;br /&gt;
== Enums ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;FileTypeChoices&amp;lt;/code&amp;gt; values ===&lt;br /&gt;
&lt;br /&gt;
The owning-resource domain (&amp;lt;code&amp;gt;spec.py&amp;lt;/code&amp;gt;). String enum.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Value&lt;br /&gt;
! Links a file to&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;patient&amp;lt;/code&amp;gt;&lt;br /&gt;
| A [[References/Patient&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;encounter&amp;lt;/code&amp;gt;&lt;br /&gt;
| An [[References/Encounter&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;consent&amp;lt;/code&amp;gt;&lt;br /&gt;
| A [[References/Consent&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;diagnostic_report&amp;lt;/code&amp;gt;&lt;br /&gt;
| A [[References/Diagnostic Report&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;service_request&amp;lt;/code&amp;gt;&lt;br /&gt;
| A [[References/Service Request&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;FileCategoryChoices&amp;lt;/code&amp;gt; values ===&lt;br /&gt;
&lt;br /&gt;
File category (&amp;lt;code&amp;gt;spec.py&amp;lt;/code&amp;gt;). String enum.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;audio&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;xray&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;identity_proof&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;unspecified&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;discharge_summary&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;consent_attachment&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Resource specs (API schema) ==&lt;br /&gt;
&lt;br /&gt;
Every spec extends &amp;lt;code&amp;gt;EMRResource&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;care/emr/resources/base.py&amp;lt;/code&amp;gt;), which supplies &amp;lt;code&amp;gt;serialize&amp;lt;/code&amp;gt; (DB → Pydantic) and &amp;lt;code&amp;gt;de_serialize&amp;lt;/code&amp;gt; (Pydantic → DB) plus the &amp;lt;code&amp;gt;perform_extra_serialization&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;perform_extra_deserialization&amp;lt;/code&amp;gt; hooks. &amp;lt;code&amp;gt;FileUpload&amp;lt;/code&amp;gt; deliberately omits &amp;lt;code&amp;gt;__store_metadata__&amp;lt;/code&amp;gt;, so its hooks move &amp;lt;code&amp;gt;mime_type&amp;lt;/code&amp;gt; in and out of &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt; by hand instead of leaning on the generic meta machinery.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Spec&lt;br /&gt;
! Role&lt;br /&gt;
! Exposes / behaviour&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FileUploadBaseSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| shared base&lt;br /&gt;
| &amp;lt;code&amp;gt;id: UUID4 | None&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;name: str&amp;lt;/code&amp;gt; (required)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FileUploadCreateSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| write · create&lt;br /&gt;
| Adds &amp;lt;code&amp;gt;original_name&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;file_type&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;file_category&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;associating_id&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mime_type&amp;lt;/code&amp;gt;. Validates &amp;lt;code&amp;gt;mime_type&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;original_name&amp;lt;/code&amp;gt;; on deserialize sets &amp;lt;code&amp;gt;_just_created=True&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;internal_name = original_name&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;meta[&amp;amp;quot;mime_type&amp;amp;quot;]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FileUploadUpdateSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| write · update&lt;br /&gt;
| Same fields as base (&amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt;) — the display name is the only thing you can edit&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FileUploadListSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| read · list&lt;br /&gt;
| Read view (fields below); resolves &amp;lt;code&amp;gt;extension&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mime_type&amp;lt;/code&amp;gt;, audit users, &amp;lt;code&amp;gt;uploaded_by&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archived_by&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;FileUploadRetrieveSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| read · detail&lt;br /&gt;
| Extends &amp;lt;code&amp;gt;FileUploadListSpec&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;signed_url&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;read_signed_url&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;internal_name&amp;lt;/code&amp;gt;; emits a write URL for just-created rows, otherwise a read URL&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ConsentFileUploadCreateSpec&amp;lt;/code&amp;gt;&lt;br /&gt;
| write · create (consent)&lt;br /&gt;
| &amp;lt;code&amp;gt;original_name&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;associating_id: UUID4&amp;lt;/code&amp;gt;; forces &amp;lt;code&amp;gt;file_type=consent&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;file_category=consent_attachment&amp;lt;/code&amp;gt; server-side&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nothing here binds to a value set or uses &amp;lt;code&amp;gt;CodeableConcept&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;Period&amp;lt;/code&amp;gt; / other &amp;lt;code&amp;gt;common&amp;lt;/code&amp;gt; types — &amp;lt;code&amp;gt;file_type&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;file_category&amp;lt;/code&amp;gt; are plain string enums.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;FileUploadCreateSpec&amp;lt;/code&amp;gt; validation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Rule&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt;&lt;br /&gt;
| Required (inherited from base)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;original_name&amp;lt;/code&amp;gt;&lt;br /&gt;
| Non-empty; run through &amp;lt;code&amp;gt;file_name_validator&amp;lt;/code&amp;gt; (&amp;lt;code&amp;gt;care/utils/models/validators.py&amp;lt;/code&amp;gt;): ≤ 255 chars, must not start with &amp;lt;code&amp;gt;.&amp;lt;/code&amp;gt;, must have an extension, extension must be in &amp;lt;code&amp;gt;ALLOWED_FILE_EXTENSIONS&amp;lt;/code&amp;gt; and not in &amp;lt;code&amp;gt;BLOCKED_FILE_EXTENSIONS&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mime_type&amp;lt;/code&amp;gt;&lt;br /&gt;
| Must be in &amp;lt;code&amp;gt;settings.ALLOWED_MIME_TYPES&amp;lt;/code&amp;gt;, else &amp;lt;code&amp;gt;&amp;amp;quot;Invalid mime type&amp;amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;file_type&amp;lt;/code&amp;gt;&lt;br /&gt;
| Must be a &amp;lt;code&amp;gt;FileTypeChoices&amp;lt;/code&amp;gt; member&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;file_category&amp;lt;/code&amp;gt;&lt;br /&gt;
| Must be a &amp;lt;code&amp;gt;FileCategoryChoices&amp;lt;/code&amp;gt; member&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;associating_id&amp;lt;/code&amp;gt;&lt;br /&gt;
| Required &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;FileUploadListSpec&amp;lt;/code&amp;gt; read fields ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! Source&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;UUID4&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;obj.external_id&amp;lt;/code&amp;gt; (set in &amp;lt;code&amp;gt;perform_extra_serialization&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;&lt;br /&gt;
| column&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;file_type&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;FileTypeChoices&amp;lt;/code&amp;gt;&lt;br /&gt;
| column&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;file_category&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;FileCategoryChoices&amp;lt;/code&amp;gt;&lt;br /&gt;
| column&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;associating_id&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;&lt;br /&gt;
| column&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;upload_completed&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
| column&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;is_archived&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;bool | None&amp;lt;/code&amp;gt;&lt;br /&gt;
| column&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;archive_reason&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;str | None&amp;lt;/code&amp;gt;&lt;br /&gt;
| column&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;archived_datetime&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;datetime | None&amp;lt;/code&amp;gt;&lt;br /&gt;
| column&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;created_date&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;datetime&amp;lt;/code&amp;gt;&lt;br /&gt;
| column&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;extension&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;&lt;br /&gt;
| derived via &amp;lt;code&amp;gt;obj.get_extension()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;mime_type&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;obj.meta.get(&amp;amp;quot;mime_type&amp;amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;uploaded_by&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;dict | None&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;UserSpec&amp;lt;/code&amp;gt; from cache (&amp;lt;code&amp;gt;obj.created_by_id&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;archived_by&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;UserSpec | None&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;UserSpec&amp;lt;/code&amp;gt; from cache (&amp;lt;code&amp;gt;obj.archived_by_id&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;created_by&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;updated_by&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;dict | None&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;serialize_audit_users&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;FileUploadRetrieveSpec&amp;lt;/code&amp;gt; extra fields ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field&lt;br /&gt;
! Type&lt;br /&gt;
! When populated&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;signed_url&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;str | None&amp;lt;/code&amp;gt;&lt;br /&gt;
| When &amp;lt;code&amp;gt;obj._just_created&amp;lt;/code&amp;gt; is truthy — a write (PUT) URL from &amp;lt;code&amp;gt;files_manager.signed_url(obj)&amp;lt;/code&amp;gt;. The upload target handed back at create time&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;read_signed_url&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;str | None&amp;lt;/code&amp;gt;&lt;br /&gt;
| Otherwise — a read (GET) URL from &amp;lt;code&amp;gt;files_manager.read_signed_url(obj)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;internal_name&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;str&amp;lt;/code&amp;gt;&lt;br /&gt;
| The storage object key (flagged in source as possibly not needing to be returned)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Methods &amp;amp;amp; save behaviour ==&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;get_extension()&amp;lt;/code&amp;gt; ===&lt;br /&gt;
&lt;br /&gt;
Derives the file extension from &amp;lt;code&amp;gt;internal_name&amp;lt;/code&amp;gt; via &amp;lt;code&amp;gt;parse_file_extension&amp;lt;/code&amp;gt;, formatted as &amp;lt;code&amp;gt;.ext&amp;lt;/code&amp;gt; (or a multi-part form like &amp;lt;code&amp;gt;.tar.gz&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;&amp;amp;quot;&amp;amp;quot;&amp;lt;/code&amp;gt; when there&amp;#039;s none. This is what surfaces to clients as the &amp;lt;code&amp;gt;extension&amp;lt;/code&amp;gt; read field.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;code&amp;gt;save()&amp;lt;/code&amp;gt; side effects ===&lt;br /&gt;
&lt;br /&gt;
On save, a random &amp;lt;code&amp;gt;internal_name&amp;lt;/code&amp;gt; is generated when &amp;lt;code&amp;gt;internal_name&amp;lt;/code&amp;gt; is empty or the row is new (&amp;lt;code&amp;gt;not self.id&amp;lt;/code&amp;gt;) and the caller has not passed &amp;lt;code&amp;gt;skip_internal_name=True&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
# A random &amp;lt;code&amp;gt;internal_name&amp;lt;/code&amp;gt; is generated as &amp;lt;code&amp;gt;uuid4() + int(time.time())&amp;lt;/code&amp;gt;.&lt;br /&gt;
# If an extension can be derived, it is appended to that random name.&lt;br /&gt;
# &amp;lt;code&amp;gt;internal_name&amp;lt;/code&amp;gt; is set before the row is persisted.&lt;br /&gt;
&lt;br /&gt;
Keeping the user-supplied &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt; out of the storage key limits PII leakage if the bucket is compromised. The inline &amp;lt;code&amp;gt;upload-file&amp;lt;/code&amp;gt; path calls &amp;lt;code&amp;gt;save(skip_internal_name=True)&amp;lt;/code&amp;gt; after uploading, so the generated key survives.&lt;br /&gt;
&lt;br /&gt;
== API integration notes ==&lt;br /&gt;
&lt;br /&gt;
=== Two upload flows ===&lt;br /&gt;
&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Signed-URL (direct-to-S3), default:&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;POST&amp;lt;/code&amp;gt; a &amp;lt;code&amp;gt;FileUploadCreateSpec&amp;lt;/code&amp;gt;. The server validates, deserializes (&amp;lt;code&amp;gt;_just_created=True&amp;lt;/code&amp;gt;), and returns &amp;lt;code&amp;gt;FileUploadRetrieveSpec&amp;lt;/code&amp;gt; carrying a write &amp;lt;code&amp;gt;signed_url&amp;lt;/code&amp;gt;. The client &amp;lt;code&amp;gt;PUT&amp;lt;/code&amp;gt;s the bytes straight to S3, then calls &amp;lt;code&amp;gt;POST .../{external_id}/mark_upload_completed/&amp;lt;/code&amp;gt; to flip &amp;lt;code&amp;gt;upload_completed=True&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Inline base64 (&amp;lt;code&amp;gt;POST .../upload-file/&amp;lt;/code&amp;gt;):&amp;#039;&amp;#039;&amp;#039; the client sends &amp;lt;code&amp;gt;original_name&amp;lt;/code&amp;gt; + base64 &amp;lt;code&amp;gt;file_data&amp;lt;/code&amp;gt;. The server decodes it, enforces &amp;lt;code&amp;gt;settings.MAX_FILE_UPLOAD_SIZE&amp;lt;/code&amp;gt; (MB), sniffs the real MIME type with &amp;lt;code&amp;gt;python-magic&amp;lt;/code&amp;gt;, re-checks &amp;lt;code&amp;gt;ALLOWED_MIME_TYPES&amp;lt;/code&amp;gt;, builds a &amp;lt;code&amp;gt;FileUploadCreateSpec&amp;lt;/code&amp;gt;, sets &amp;lt;code&amp;gt;_just_created=False&amp;lt;/code&amp;gt;, uploads via &amp;lt;code&amp;gt;files_manager.put_object&amp;lt;/code&amp;gt;, sets &amp;lt;code&amp;gt;upload_completed=True&amp;lt;/code&amp;gt;, and returns &amp;lt;code&amp;gt;FileUploadRetrieveSpec&amp;lt;/code&amp;gt; — so the response carries &amp;lt;code&amp;gt;read_signed_url&amp;lt;/code&amp;gt;, not a write URL.&lt;br /&gt;
&lt;br /&gt;
=== Server-maintained behaviour ===&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;internal_name&amp;lt;/code&amp;gt; is platform-maintained — never set it from a client; the model generates a random PII-free key.&lt;br /&gt;
* &amp;lt;code&amp;gt;mime_type&amp;lt;/code&amp;gt; lives in &amp;lt;code&amp;gt;meta&amp;lt;/code&amp;gt;, not a column. &amp;lt;code&amp;gt;FileUploadCreateSpec&amp;lt;/code&amp;gt; writes it and serialization reads it back. On the inline path it is re-derived from file content (&amp;lt;code&amp;gt;magic.from_buffer&amp;lt;/code&amp;gt;) rather than trusted from the client.&lt;br /&gt;
* &amp;lt;code&amp;gt;associating_id&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;file_type&amp;lt;/code&amp;gt; together link a file to its owning resource. &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt; requires both as query params and returns only &amp;lt;code&amp;gt;upload_completed=True&amp;lt;/code&amp;gt; rows.&lt;br /&gt;
* Every action runs &amp;lt;code&amp;gt;file_authorizer(user, file_type, associating_id, &amp;amp;quot;read&amp;amp;quot;|&amp;amp;quot;write&amp;amp;quot;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Archival (&amp;lt;code&amp;gt;POST .../{external_id}/archive/&amp;lt;/code&amp;gt;, body &amp;lt;code&amp;gt;{ archive_reason }&amp;lt;/code&amp;gt;) sets &amp;lt;code&amp;gt;is_archived&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archive_reason&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archived_datetime&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;archived_by&amp;lt;/code&amp;gt; server-side and returns &amp;lt;code&amp;gt;FileUploadListSpec&amp;lt;/code&amp;gt;. This soft state is separate from the &amp;lt;code&amp;gt;EMRBaseModel&amp;lt;/code&amp;gt; soft-delete (&amp;lt;code&amp;gt;deleted&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &amp;lt;code&amp;gt;mark_upload_completed&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;archive&amp;lt;/code&amp;gt; both return &amp;lt;code&amp;gt;FileUploadListSpec&amp;lt;/code&amp;gt; (no signed URL).&lt;br /&gt;
&lt;br /&gt;
{{Related}}&lt;/div&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
</feed>