mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	Enhancement: shared icon & shared by me filter (#4859)
This commit is contained in:
		@@ -80,7 +80,7 @@ django_checks() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
search_index() {
 | 
					search_index() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local -r index_version=7
 | 
						local -r index_version=8
 | 
				
			||||||
	local -r index_version_file=${DATA_DIR}/.index_version
 | 
						local -r index_version_file=${DATA_DIR}/.index_version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if [[ (! -f "${index_version_file}") || $(<"${index_version_file}") != "$index_version" ]]; then
 | 
						if [[ (! -f "${index_version_file}") || $(<"${index_version_file}") != "$index_version" ]]; then
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1657,7 +1657,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/permissions-filter-dropdown/permissions-filter-dropdown.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/permissions-filter-dropdown/permissions-filter-dropdown.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">68</context>
 | 
					          <context context-type="linenumber">78</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="2941198503117307737" datatype="html">
 | 
					      <trans-unit id="2941198503117307737" datatype="html">
 | 
				
			||||||
@@ -1721,7 +1721,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">83</context>
 | 
					          <context context-type="linenumber">89</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/manage/consumption-templates/consumption-templates.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/manage/consumption-templates/consumption-templates.component.html</context>
 | 
				
			||||||
@@ -3670,18 +3670,25 @@
 | 
				
			|||||||
          <context context-type="linenumber">38</context>
 | 
					          <context context-type="linenumber">38</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="175385209536581523" datatype="html">
 | 
				
			||||||
 | 
					        <source>Shared by me</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/common/permissions-filter-dropdown/permissions-filter-dropdown.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">48</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="5151074932731293042" datatype="html">
 | 
					      <trans-unit id="5151074932731293042" datatype="html">
 | 
				
			||||||
        <source>Unowned</source>
 | 
					        <source>Unowned</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/permissions-filter-dropdown/permissions-filter-dropdown.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/permissions-filter-dropdown/permissions-filter-dropdown.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">48</context>
 | 
					          <context context-type="linenumber">58</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8999708063434507268" datatype="html">
 | 
					      <trans-unit id="8999708063434507268" datatype="html">
 | 
				
			||||||
        <source>Hide unowned</source>
 | 
					        <source>Hide unowned</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/common/permissions-filter-dropdown/permissions-filter-dropdown.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/common/permissions-filter-dropdown/permissions-filter-dropdown.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">77</context>
 | 
					          <context context-type="linenumber">87</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8650499415827640724" datatype="html">
 | 
					      <trans-unit id="8650499415827640724" datatype="html">
 | 
				
			||||||
@@ -4012,7 +4019,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">203</context>
 | 
					          <context context-type="linenumber">204</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
 | 
					          <context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
 | 
				
			||||||
@@ -4073,7 +4080,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">99</context>
 | 
					          <context context-type="linenumber">105</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="872092479747931526" datatype="html">
 | 
					      <trans-unit id="872092479747931526" datatype="html">
 | 
				
			||||||
@@ -5007,11 +5014,26 @@
 | 
				
			|||||||
          <context context-type="linenumber">58,59</context>
 | 
					          <context context-type="linenumber">58,59</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
 | 
					      <trans-unit id="5739581984228459958" datatype="html">
 | 
				
			||||||
 | 
					        <source>Shared</source>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">119</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/document-list/document-card-small/document-card-small.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">84</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/pipes/username.pipe.ts</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">33</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="2332107018974972998" datatype="html">
 | 
					      <trans-unit id="2332107018974972998" datatype="html">
 | 
				
			||||||
        <source>Score:</source>
 | 
					        <source>Score:</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/document-card-large/document-card-large.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">116</context>
 | 
					          <context context-type="linenumber">122</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3661756380991326939" datatype="html">
 | 
					      <trans-unit id="3661756380991326939" datatype="html">
 | 
				
			||||||
@@ -5138,7 +5160,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">208</context>
 | 
					          <context context-type="linenumber">209</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
 | 
					          <context context-type="sourcefile">src/app/services/rest/document.service.ts</context>
 | 
				
			||||||
@@ -5254,14 +5276,14 @@
 | 
				
			|||||||
            )?.name"/></source>
 | 
					            )?.name"/></source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">120,122</context>
 | 
					          <context context-type="linenumber">121,123</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8170755470576301659" datatype="html">
 | 
					      <trans-unit id="8170755470576301659" datatype="html">
 | 
				
			||||||
        <source>Without correspondent</source>
 | 
					        <source>Without correspondent</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">124</context>
 | 
					          <context context-type="linenumber">125</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="317796810569008208" datatype="html">
 | 
					      <trans-unit id="317796810569008208" datatype="html">
 | 
				
			||||||
@@ -5270,14 +5292,14 @@
 | 
				
			|||||||
            )?.name"/></source>
 | 
					            )?.name"/></source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">130,132</context>
 | 
					          <context context-type="linenumber">131,133</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="4362173610367509215" datatype="html">
 | 
					      <trans-unit id="4362173610367509215" datatype="html">
 | 
				
			||||||
        <source>Without document type</source>
 | 
					        <source>Without document type</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">134</context>
 | 
					          <context context-type="linenumber">135</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="232202047340644471" datatype="html">
 | 
					      <trans-unit id="232202047340644471" datatype="html">
 | 
				
			||||||
@@ -5286,14 +5308,14 @@
 | 
				
			|||||||
            )?.name"/></source>
 | 
					            )?.name"/></source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">140,142</context>
 | 
					          <context context-type="linenumber">141,143</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1562820715074533164" datatype="html">
 | 
					      <trans-unit id="1562820715074533164" datatype="html">
 | 
				
			||||||
        <source>Without storage path</source>
 | 
					        <source>Without storage path</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">144</context>
 | 
					          <context context-type="linenumber">145</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8180755793012580465" datatype="html">
 | 
					      <trans-unit id="8180755793012580465" datatype="html">
 | 
				
			||||||
@@ -5301,112 +5323,112 @@
 | 
				
			|||||||
            ?.name"/></source>
 | 
					            ?.name"/></source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">148,149</context>
 | 
					          <context context-type="linenumber">149,150</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6494566478302448576" datatype="html">
 | 
					      <trans-unit id="6494566478302448576" datatype="html">
 | 
				
			||||||
        <source>Without any tag</source>
 | 
					        <source>Without any tag</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">153</context>
 | 
					          <context context-type="linenumber">154</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6523384805359286307" datatype="html">
 | 
					      <trans-unit id="6523384805359286307" datatype="html">
 | 
				
			||||||
        <source>Title: <x id="PH" equiv-text="rule.value"/></source>
 | 
					        <source>Title: <x id="PH" equiv-text="rule.value"/></source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">157</context>
 | 
					          <context context-type="linenumber">158</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1872523635812236432" datatype="html">
 | 
					      <trans-unit id="1872523635812236432" datatype="html">
 | 
				
			||||||
        <source>ASN: <x id="PH" equiv-text="rule.value"/></source>
 | 
					        <source>ASN: <x id="PH" equiv-text="rule.value"/></source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">160</context>
 | 
					          <context context-type="linenumber">161</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="102674688969746976" datatype="html">
 | 
					      <trans-unit id="102674688969746976" datatype="html">
 | 
				
			||||||
        <source>Owner: <x id="PH" equiv-text="rule.value"/></source>
 | 
					        <source>Owner: <x id="PH" equiv-text="rule.value"/></source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">163</context>
 | 
					          <context context-type="linenumber">164</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3550877650686009106" datatype="html">
 | 
					      <trans-unit id="3550877650686009106" datatype="html">
 | 
				
			||||||
        <source>Owner not in: <x id="PH" equiv-text="rule.value"/></source>
 | 
					        <source>Owner not in: <x id="PH" equiv-text="rule.value"/></source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">166</context>
 | 
					          <context context-type="linenumber">167</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1082034558646673343" datatype="html">
 | 
					      <trans-unit id="1082034558646673343" datatype="html">
 | 
				
			||||||
        <source>Without an owner</source>
 | 
					        <source>Without an owner</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">169</context>
 | 
					          <context context-type="linenumber">170</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3100631071441658964" datatype="html">
 | 
					      <trans-unit id="3100631071441658964" datatype="html">
 | 
				
			||||||
        <source>Title & content</source>
 | 
					        <source>Title & content</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">206</context>
 | 
					          <context context-type="linenumber">207</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="9149498548977462220" datatype="html">
 | 
					      <trans-unit id="9149498548977462220" datatype="html">
 | 
				
			||||||
        <source>Custom fields</source>
 | 
					        <source>Custom fields</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">211</context>
 | 
					          <context context-type="linenumber">212</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="1010505078885609376" datatype="html">
 | 
					      <trans-unit id="1010505078885609376" datatype="html">
 | 
				
			||||||
        <source>Advanced search</source>
 | 
					        <source>Advanced search</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">215</context>
 | 
					          <context context-type="linenumber">216</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="2649431021108393503" datatype="html">
 | 
					      <trans-unit id="2649431021108393503" datatype="html">
 | 
				
			||||||
        <source>More like</source>
 | 
					        <source>More like</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">221</context>
 | 
					          <context context-type="linenumber">222</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="3697582909018473071" datatype="html">
 | 
					      <trans-unit id="3697582909018473071" datatype="html">
 | 
				
			||||||
        <source>equals</source>
 | 
					        <source>equals</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">240</context>
 | 
					          <context context-type="linenumber">241</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="5325481293405718739" datatype="html">
 | 
					      <trans-unit id="5325481293405718739" datatype="html">
 | 
				
			||||||
        <source>is empty</source>
 | 
					        <source>is empty</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">244</context>
 | 
					          <context context-type="linenumber">245</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="6166785695326182482" datatype="html">
 | 
					      <trans-unit id="6166785695326182482" datatype="html">
 | 
				
			||||||
        <source>is not empty</source>
 | 
					        <source>is not empty</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">248</context>
 | 
					          <context context-type="linenumber">249</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="4686622206659266699" datatype="html">
 | 
					      <trans-unit id="4686622206659266699" datatype="html">
 | 
				
			||||||
        <source>greater than</source>
 | 
					        <source>greater than</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">252</context>
 | 
					          <context context-type="linenumber">253</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8014012170270529279" datatype="html">
 | 
					      <trans-unit id="8014012170270529279" datatype="html">
 | 
				
			||||||
        <source>less than</source>
 | 
					        <source>less than</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/document-list/filter-editor/filter-editor.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">256</context>
 | 
					          <context context-type="linenumber">257</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="7210076240260527720" datatype="html">
 | 
					      <trans-unit id="7210076240260527720" datatype="html">
 | 
				
			||||||
@@ -6297,13 +6319,6 @@
 | 
				
			|||||||
          <context context-type="linenumber">11</context>
 | 
					          <context context-type="linenumber">11</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="5739581984228459958" datatype="html">
 | 
					 | 
				
			||||||
        <source>Shared</source>
 | 
					 | 
				
			||||||
        <context-group purpose="location">
 | 
					 | 
				
			||||||
          <context context-type="sourcefile">src/app/pipes/username.pipe.ts</context>
 | 
					 | 
				
			||||||
          <context context-type="linenumber">33</context>
 | 
					 | 
				
			||||||
        </context-group>
 | 
					 | 
				
			||||||
      </trans-unit>
 | 
					 | 
				
			||||||
      <trans-unit id="2807800733729323332" datatype="html">
 | 
					      <trans-unit id="2807800733729323332" datatype="html">
 | 
				
			||||||
        <source>Yes</source>
 | 
					        <source>Yes</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,16 @@
 | 
				
			|||||||
                    <small i18n>Shared with me</small>
 | 
					                    <small i18n>Shared with me</small>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
 | 
					            <button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="setFilter(OwnerFilterType.SHARED_BY_ME)" [disabled]="disabled">
 | 
				
			||||||
 | 
					                <div class="selected-icon me-1">
 | 
				
			||||||
 | 
					                    <svg *ngIf="selectionModel.ownerFilter === OwnerFilterType.SHARED_BY_ME" fill="currentColor" class="buttonicon-sm">
 | 
				
			||||||
 | 
					                        <use xlink:href="assets/bootstrap-icons.svg#check"/>
 | 
				
			||||||
 | 
					                    </svg>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="me-1">
 | 
				
			||||||
 | 
					                    <small i18n>Shared by me</small>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
            <button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="setFilter(OwnerFilterType.UNOWNED)" [disabled]="disabled">
 | 
					            <button class="list-group-item list-group-item-action d-flex align-items-center p-2 border-top-0 border-start-0 border-end-0 border-bottom" role="menuitem" (click)="setFilter(OwnerFilterType.UNOWNED)" [disabled]="disabled">
 | 
				
			||||||
                <div class="selected-icon me-1">
 | 
					                <div class="selected-icon me-1">
 | 
				
			||||||
                    <svg *ngIf="selectionModel.ownerFilter === OwnerFilterType.UNOWNED" fill="currentColor" class="buttonicon-sm">
 | 
					                    <svg *ngIf="selectionModel.ownerFilter === OwnerFilterType.UNOWNED" fill="currentColor" class="buttonicon-sm">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -145,6 +145,15 @@ describe('PermissionsFilterDropdownComponent', () => {
 | 
				
			|||||||
      userID: null,
 | 
					      userID: null,
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    component.setFilter(OwnerFilterType.SHARED_BY_ME)
 | 
				
			||||||
 | 
					    expect(ownerFilterSetResult).toEqual({
 | 
				
			||||||
 | 
					      excludeUsers: [],
 | 
				
			||||||
 | 
					      hideUnowned: false,
 | 
				
			||||||
 | 
					      includeUsers: [],
 | 
				
			||||||
 | 
					      ownerFilter: OwnerFilterType.SHARED_BY_ME,
 | 
				
			||||||
 | 
					      userID: currentUserID,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    component.setFilter(OwnerFilterType.UNOWNED)
 | 
					    component.setFilter(OwnerFilterType.UNOWNED)
 | 
				
			||||||
    expect(ownerFilterSetResult).toEqual({
 | 
					    expect(ownerFilterSetResult).toEqual({
 | 
				
			||||||
      excludeUsers: [],
 | 
					      excludeUsers: [],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,7 @@ export enum OwnerFilterType {
 | 
				
			|||||||
  NOT_SELF = 2,
 | 
					  NOT_SELF = 2,
 | 
				
			||||||
  OTHERS = 3,
 | 
					  OTHERS = 3,
 | 
				
			||||||
  UNOWNED = 4,
 | 
					  UNOWNED = 4,
 | 
				
			||||||
 | 
					  SHARED_BY_ME = 5,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
@@ -108,6 +109,13 @@ export class PermissionsFilterDropdownComponent extends ComponentWithPermissions
 | 
				
			|||||||
      this.selectionModel.includeUsers = []
 | 
					      this.selectionModel.includeUsers = []
 | 
				
			||||||
      this.selectionModel.excludeUsers = []
 | 
					      this.selectionModel.excludeUsers = []
 | 
				
			||||||
      this.selectionModel.hideUnowned = false
 | 
					      this.selectionModel.hideUnowned = false
 | 
				
			||||||
 | 
					    } else if (
 | 
				
			||||||
 | 
					      this.selectionModel.ownerFilter === OwnerFilterType.SHARED_BY_ME
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      this.selectionModel.userID = this.settingsService.currentUser.id
 | 
				
			||||||
 | 
					      this.selectionModel.includeUsers = []
 | 
				
			||||||
 | 
					      this.selectionModel.excludeUsers = []
 | 
				
			||||||
 | 
					      this.selectionModel.hideUnowned = false
 | 
				
			||||||
    } else if (this.selectionModel.ownerFilter === OwnerFilterType.UNOWNED) {
 | 
					    } else if (this.selectionModel.ownerFilter === OwnerFilterType.UNOWNED) {
 | 
				
			||||||
      this.selectionModel.userID = null
 | 
					      this.selectionModel.userID = null
 | 
				
			||||||
      this.selectionModel.includeUsers = []
 | 
					      this.selectionModel.includeUsers = []
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -112,6 +112,12 @@
 | 
				
			|||||||
              </svg>
 | 
					              </svg>
 | 
				
			||||||
              <small>{{document.owner | username}}</small>
 | 
					              <small>{{document.owner | username}}</small>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div *ngIf="document.is_shared_by_requester" class="list-group-item bg-light text-dark p-1 border-0">
 | 
				
			||||||
 | 
					              <svg class="metadata-icon me-2 text-muted" fill="currentColor">
 | 
				
			||||||
 | 
					                <use xlink:href="assets/bootstrap-icons.svg#people-fill"/>
 | 
				
			||||||
 | 
					              </svg>
 | 
				
			||||||
 | 
					              <small i18n>Shared</small>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
            <div *ngIf="document.__search_hit__?.score" class="list-group-item bg-light text-dark border-0 d-flex p-0 ps-4 search-score">
 | 
					            <div *ngIf="document.__search_hit__?.score" class="list-group-item bg-light text-dark border-0 d-flex p-0 ps-4 search-score">
 | 
				
			||||||
              <small class="text-muted" i18n>Score:</small>
 | 
					              <small class="text-muted" i18n>Score:</small>
 | 
				
			||||||
              <ngb-progressbar [type]="searchScoreClass" [value]="document.__search_hit__.score" class="search-score-bar mx-2 mt-1" [max]="1"></ngb-progressbar>
 | 
					              <ngb-progressbar [type]="searchScoreClass" [value]="document.__search_hit__.score" class="search-score-bar mx-2 mt-1" [max]="1"></ngb-progressbar>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,6 +77,12 @@
 | 
				
			|||||||
          </svg>
 | 
					          </svg>
 | 
				
			||||||
          <small>{{document.owner | username}}</small>
 | 
					          <small>{{document.owner | username}}</small>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div *ngIf="document.is_shared_by_requester" class="ps-0 p-1">
 | 
				
			||||||
 | 
					          <svg class="metadata-icon me-2 text-muted" fill="currentColor">
 | 
				
			||||||
 | 
					            <use xlink:href="assets/bootstrap-icons.svg#people-fill"/>
 | 
				
			||||||
 | 
					          </svg>
 | 
				
			||||||
 | 
					          <small i18n>Shared</small>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="d-flex justify-content-between align-items-center">
 | 
					      <div class="d-flex justify-content-between align-items-center">
 | 
				
			||||||
        <div class="btn-group w-100">
 | 
					        <div class="btn-group w-100">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,7 @@ import {
 | 
				
			|||||||
  FILTER_OWNER_DOES_NOT_INCLUDE,
 | 
					  FILTER_OWNER_DOES_NOT_INCLUDE,
 | 
				
			||||||
  FILTER_OWNER_ISNULL,
 | 
					  FILTER_OWNER_ISNULL,
 | 
				
			||||||
  FILTER_CUSTOM_FIELDS,
 | 
					  FILTER_CUSTOM_FIELDS,
 | 
				
			||||||
 | 
					  FILTER_SHARED_BY_USER,
 | 
				
			||||||
} from 'src/app/data/filter-rule-type'
 | 
					} from 'src/app/data/filter-rule-type'
 | 
				
			||||||
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'
 | 
					import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent'
 | 
				
			||||||
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'
 | 
					import { PaperlessDocumentType } from 'src/app/data/paperless-document-type'
 | 
				
			||||||
@@ -826,6 +827,16 @@ describe('FilterEditorComponent', () => {
 | 
				
			|||||||
    expect(component.permissionsSelectionModel.hideUnowned).toBeTruthy()
 | 
					    expect(component.permissionsSelectionModel.hideUnowned).toBeTruthy()
 | 
				
			||||||
  }))
 | 
					  }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should ingest filter rules for shared by me', fakeAsync(() => {
 | 
				
			||||||
 | 
					    component.filterRules = [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        rule_type: FILTER_SHARED_BY_USER,
 | 
				
			||||||
 | 
					        value: '2',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    expect(component.permissionsSelectionModel.userID).toEqual(2)
 | 
				
			||||||
 | 
					  }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // GET filterRules
 | 
					  // GET filterRules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should convert user input to correct filter rules on text field search title + content', fakeAsync(() => {
 | 
					  it('should convert user input to correct filter rules on text field search title + content', fakeAsync(() => {
 | 
				
			||||||
@@ -1453,13 +1464,28 @@ describe('FilterEditorComponent', () => {
 | 
				
			|||||||
    ])
 | 
					    ])
 | 
				
			||||||
  }))
 | 
					  }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should convert user input to correct filter on permissions select unowned', fakeAsync(() => {
 | 
					  it('should convert user input to correct filter on permissions select shared by me', fakeAsync(() => {
 | 
				
			||||||
    const permissionsDropdown = fixture.debugElement.query(
 | 
					    const permissionsDropdown = fixture.debugElement.query(
 | 
				
			||||||
      By.directive(PermissionsFilterDropdownComponent)
 | 
					      By.directive(PermissionsFilterDropdownComponent)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    const unownedButton = permissionsDropdown.queryAll(By.css('button'))[4]
 | 
					    const unownedButton = permissionsDropdown.queryAll(By.css('button'))[4]
 | 
				
			||||||
    unownedButton.triggerEventHandler('click')
 | 
					    unownedButton.triggerEventHandler('click')
 | 
				
			||||||
    fixture.detectChanges()
 | 
					    fixture.detectChanges()
 | 
				
			||||||
 | 
					    expect(component.filterRules).toEqual([
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        rule_type: FILTER_SHARED_BY_USER,
 | 
				
			||||||
 | 
					        value: '1',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ])
 | 
				
			||||||
 | 
					  }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should convert user input to correct filter on permissions select unowned', fakeAsync(() => {
 | 
				
			||||||
 | 
					    const permissionsDropdown = fixture.debugElement.query(
 | 
				
			||||||
 | 
					      By.directive(PermissionsFilterDropdownComponent)
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    const unownedButton = permissionsDropdown.queryAll(By.css('button'))[5]
 | 
				
			||||||
 | 
					    unownedButton.triggerEventHandler('click')
 | 
				
			||||||
 | 
					    fixture.detectChanges()
 | 
				
			||||||
    expect(component.filterRules).toEqual([
 | 
					    expect(component.filterRules).toEqual([
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        rule_type: FILTER_OWNER_ISNULL,
 | 
					        rule_type: FILTER_OWNER_ISNULL,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,6 +49,7 @@ import {
 | 
				
			|||||||
  FILTER_OWNER_ISNULL,
 | 
					  FILTER_OWNER_ISNULL,
 | 
				
			||||||
  FILTER_OWNER_ANY,
 | 
					  FILTER_OWNER_ANY,
 | 
				
			||||||
  FILTER_CUSTOM_FIELDS,
 | 
					  FILTER_CUSTOM_FIELDS,
 | 
				
			||||||
 | 
					  FILTER_SHARED_BY_USER,
 | 
				
			||||||
} from 'src/app/data/filter-rule-type'
 | 
					} from 'src/app/data/filter-rule-type'
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  FilterableDropdownSelectionModel,
 | 
					  FilterableDropdownSelectionModel,
 | 
				
			||||||
@@ -503,6 +504,12 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
              parseInt(rule.value, 10)
 | 
					              parseInt(rule.value, 10)
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
          break
 | 
					          break
 | 
				
			||||||
 | 
					        case FILTER_SHARED_BY_USER:
 | 
				
			||||||
 | 
					          this.permissionsSelectionModel.ownerFilter =
 | 
				
			||||||
 | 
					            OwnerFilterType.SHARED_BY_ME
 | 
				
			||||||
 | 
					          if (rule.value)
 | 
				
			||||||
 | 
					            this.permissionsSelectionModel.userID = parseInt(rule.value, 10)
 | 
				
			||||||
 | 
					          break
 | 
				
			||||||
        case FILTER_OWNER_ISNULL:
 | 
					        case FILTER_OWNER_ISNULL:
 | 
				
			||||||
          if (rule.value === 'true' || rule.value === '1') {
 | 
					          if (rule.value === 'true' || rule.value === '1') {
 | 
				
			||||||
            this.permissionsSelectionModel.hideUnowned = false
 | 
					            this.permissionsSelectionModel.hideUnowned = false
 | 
				
			||||||
@@ -801,6 +808,13 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
        rule_type: FILTER_OWNER_ANY,
 | 
					        rule_type: FILTER_OWNER_ANY,
 | 
				
			||||||
        value: this.permissionsSelectionModel.includeUsers?.join(','),
 | 
					        value: this.permissionsSelectionModel.includeUsers?.join(','),
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
					    } else if (
 | 
				
			||||||
 | 
					      this.permissionsSelectionModel.ownerFilter == OwnerFilterType.SHARED_BY_ME
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      filterRules.push({
 | 
				
			||||||
 | 
					        rule_type: FILTER_SHARED_BY_USER,
 | 
				
			||||||
 | 
					        value: this.permissionsSelectionModel.userID.toString(),
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
    } else if (
 | 
					    } else if (
 | 
				
			||||||
      this.permissionsSelectionModel.ownerFilter == OwnerFilterType.UNOWNED
 | 
					      this.permissionsSelectionModel.ownerFilter == OwnerFilterType.UNOWNED
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,7 @@ export const FILTER_OWNER = 32
 | 
				
			|||||||
export const FILTER_OWNER_ANY = 33
 | 
					export const FILTER_OWNER_ANY = 33
 | 
				
			||||||
export const FILTER_OWNER_ISNULL = 34
 | 
					export const FILTER_OWNER_ISNULL = 34
 | 
				
			||||||
export const FILTER_OWNER_DOES_NOT_INCLUDE = 35
 | 
					export const FILTER_OWNER_DOES_NOT_INCLUDE = 35
 | 
				
			||||||
 | 
					export const FILTER_SHARED_BY_USER = 37
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const FILTER_CUSTOM_FIELDS = 36
 | 
					export const FILTER_CUSTOM_FIELDS = 36
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -273,6 +274,12 @@ export const FILTER_RULE_TYPES: FilterRuleType[] = [
 | 
				
			|||||||
    datatype: 'number',
 | 
					    datatype: 'number',
 | 
				
			||||||
    multi: true,
 | 
					    multi: true,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: FILTER_SHARED_BY_USER,
 | 
				
			||||||
 | 
					    filtervar: 'shared_by__id',
 | 
				
			||||||
 | 
					    datatype: 'number',
 | 
				
			||||||
 | 
					    multi: true,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    id: FILTER_CUSTOM_FIELDS,
 | 
					    id: FILTER_CUSTOM_FIELDS,
 | 
				
			||||||
    filtervar: 'custom_fields__icontains',
 | 
					    filtervar: 'custom_fields__icontains',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,4 +17,6 @@ export interface ObjectWithPermissions extends ObjectWithId {
 | 
				
			|||||||
  permissions?: PermissionsObject
 | 
					  permissions?: PermissionsObject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  user_can_change?: boolean
 | 
					  user_can_change?: boolean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  is_shared_by_requester?: boolean
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,12 @@
 | 
				
			|||||||
 | 
					from django.contrib.contenttypes.models import ContentType
 | 
				
			||||||
 | 
					from django.db.models import Count
 | 
				
			||||||
 | 
					from django.db.models import OuterRef
 | 
				
			||||||
from django.db.models import Q
 | 
					from django.db.models import Q
 | 
				
			||||||
from django_filters.rest_framework import BooleanFilter
 | 
					from django_filters.rest_framework import BooleanFilter
 | 
				
			||||||
from django_filters.rest_framework import Filter
 | 
					from django_filters.rest_framework import Filter
 | 
				
			||||||
from django_filters.rest_framework import FilterSet
 | 
					from django_filters.rest_framework import FilterSet
 | 
				
			||||||
 | 
					from guardian.utils import get_group_obj_perms_model
 | 
				
			||||||
 | 
					from guardian.utils import get_user_obj_perms_model
 | 
				
			||||||
from rest_framework_guardian.filters import ObjectPermissionsFilter
 | 
					from rest_framework_guardian.filters import ObjectPermissionsFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from documents.models import Correspondent
 | 
					from documents.models import Correspondent
 | 
				
			||||||
@@ -101,6 +106,39 @@ class TitleContentFilter(Filter):
 | 
				
			|||||||
            return qs
 | 
					            return qs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SharedByUser(Filter):
 | 
				
			||||||
 | 
					    def filter(self, qs, value):
 | 
				
			||||||
 | 
					        ctype = ContentType.objects.get_for_model(self.model)
 | 
				
			||||||
 | 
					        UserObjectPermission = get_user_obj_perms_model()
 | 
				
			||||||
 | 
					        GroupObjectPermission = get_group_obj_perms_model()
 | 
				
			||||||
 | 
					        return (
 | 
				
			||||||
 | 
					            qs.filter(
 | 
				
			||||||
 | 
					                owner_id=value,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .annotate(
 | 
				
			||||||
 | 
					                num_shared_users=Count(
 | 
				
			||||||
 | 
					                    UserObjectPermission.objects.filter(
 | 
				
			||||||
 | 
					                        content_type=ctype,
 | 
				
			||||||
 | 
					                        object_pk=OuterRef("pk"),
 | 
				
			||||||
 | 
					                    ).values("user_id"),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .annotate(
 | 
				
			||||||
 | 
					                num_shared_groups=Count(
 | 
				
			||||||
 | 
					                    GroupObjectPermission.objects.filter(
 | 
				
			||||||
 | 
					                        content_type=ctype,
 | 
				
			||||||
 | 
					                        object_pk=OuterRef("pk"),
 | 
				
			||||||
 | 
					                    ).values("group_id"),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .filter(
 | 
				
			||||||
 | 
					                Q(num_shared_users__gt=0) | Q(num_shared_groups__gt=0),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            if value is not None
 | 
				
			||||||
 | 
					            else qs
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CustomFieldsFilter(Filter):
 | 
					class CustomFieldsFilter(Filter):
 | 
				
			||||||
    def filter(self, qs, value):
 | 
					    def filter(self, qs, value):
 | 
				
			||||||
        if value:
 | 
					        if value:
 | 
				
			||||||
@@ -144,6 +182,8 @@ class DocumentFilterSet(FilterSet):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    custom_fields__icontains = CustomFieldsFilter()
 | 
					    custom_fields__icontains = CustomFieldsFilter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    shared_by__id = SharedByUser()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Document
 | 
					        model = Document
 | 
				
			||||||
        fields = {
 | 
					        fields = {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,6 +75,7 @@ def get_schema():
 | 
				
			|||||||
        viewer_id=KEYWORD(commas=True),
 | 
					        viewer_id=KEYWORD(commas=True),
 | 
				
			||||||
        checksum=TEXT(),
 | 
					        checksum=TEXT(),
 | 
				
			||||||
        original_filename=TEXT(sortable=True),
 | 
					        original_filename=TEXT(sortable=True),
 | 
				
			||||||
 | 
					        is_shared=BOOLEAN(),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -167,6 +168,7 @@ def update_document(writer: AsyncWriter, doc: Document):
 | 
				
			|||||||
        viewer_id=viewer_ids if viewer_ids else None,
 | 
					        viewer_id=viewer_ids if viewer_ids else None,
 | 
				
			||||||
        checksum=doc.checksum,
 | 
					        checksum=doc.checksum,
 | 
				
			||||||
        original_filename=doc.original_filename,
 | 
					        original_filename=doc.original_filename,
 | 
				
			||||||
 | 
					        is_shared=len(viewer_ids) > 0,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -194,6 +196,7 @@ class DelayedQuery:
 | 
				
			|||||||
        "document_type": ("type", ["id", "id__in", "id__none", "isnull"]),
 | 
					        "document_type": ("type", ["id", "id__in", "id__none", "isnull"]),
 | 
				
			||||||
        "storage_path": ("path", ["id", "id__in", "id__none", "isnull"]),
 | 
					        "storage_path": ("path", ["id", "id__in", "id__none", "isnull"]),
 | 
				
			||||||
        "owner": ("owner", ["id", "id__in", "id__none", "isnull"]),
 | 
					        "owner": ("owner", ["id", "id__in", "id__none", "isnull"]),
 | 
				
			||||||
 | 
					        "shared_by": ("shared_by", ["id"]),
 | 
				
			||||||
        "tags": ("tag", ["id__all", "id__in", "id__none"]),
 | 
					        "tags": ("tag", ["id__all", "id__in", "id__none"]),
 | 
				
			||||||
        "added": ("added", ["date__lt", "date__gt"]),
 | 
					        "added": ("added", ["date__lt", "date__gt"]),
 | 
				
			||||||
        "created": ("created", ["date__lt", "date__gt"]),
 | 
					        "created": ("created", ["date__lt", "date__gt"]),
 | 
				
			||||||
@@ -233,7 +236,11 @@ class DelayedQuery:
 | 
				
			|||||||
                continue
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if query_filter == "id":
 | 
					            if query_filter == "id":
 | 
				
			||||||
                criterias.append(query.Term(f"{field}_id", value))
 | 
					                if param == "shared_by":
 | 
				
			||||||
 | 
					                    criterias.append(query.Term("is_shared", True))
 | 
				
			||||||
 | 
					                    criterias.append(query.Term("owner_id", value))
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    criterias.append(query.Term(f"{field}_id", value))
 | 
				
			||||||
            elif query_filter == "id__in":
 | 
					            elif query_filter == "id__in":
 | 
				
			||||||
                in_filter = []
 | 
					                in_filter = []
 | 
				
			||||||
                for object_id in value.split(","):
 | 
					                for object_id in value.split(","):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					# Generated by Django 4.2.7 on 2023-12-09 18:13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations
 | 
				
			||||||
 | 
					from django.db import models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ("documents", "1042_consumptiontemplate_assign_custom_fields_and_more"),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AlterField(
 | 
				
			||||||
 | 
					            model_name="savedviewfilterrule",
 | 
				
			||||||
 | 
					            name="rule_type",
 | 
				
			||||||
 | 
					            field=models.PositiveIntegerField(
 | 
				
			||||||
 | 
					                choices=[
 | 
				
			||||||
 | 
					                    (0, "title contains"),
 | 
				
			||||||
 | 
					                    (1, "content contains"),
 | 
				
			||||||
 | 
					                    (2, "ASN is"),
 | 
				
			||||||
 | 
					                    (3, "correspondent is"),
 | 
				
			||||||
 | 
					                    (4, "document type is"),
 | 
				
			||||||
 | 
					                    (5, "is in inbox"),
 | 
				
			||||||
 | 
					                    (6, "has tag"),
 | 
				
			||||||
 | 
					                    (7, "has any tag"),
 | 
				
			||||||
 | 
					                    (8, "created before"),
 | 
				
			||||||
 | 
					                    (9, "created after"),
 | 
				
			||||||
 | 
					                    (10, "created year is"),
 | 
				
			||||||
 | 
					                    (11, "created month is"),
 | 
				
			||||||
 | 
					                    (12, "created day is"),
 | 
				
			||||||
 | 
					                    (13, "added before"),
 | 
				
			||||||
 | 
					                    (14, "added after"),
 | 
				
			||||||
 | 
					                    (15, "modified before"),
 | 
				
			||||||
 | 
					                    (16, "modified after"),
 | 
				
			||||||
 | 
					                    (17, "does not have tag"),
 | 
				
			||||||
 | 
					                    (18, "does not have ASN"),
 | 
				
			||||||
 | 
					                    (19, "title or content contains"),
 | 
				
			||||||
 | 
					                    (20, "fulltext query"),
 | 
				
			||||||
 | 
					                    (21, "more like this"),
 | 
				
			||||||
 | 
					                    (22, "has tags in"),
 | 
				
			||||||
 | 
					                    (23, "ASN greater than"),
 | 
				
			||||||
 | 
					                    (24, "ASN less than"),
 | 
				
			||||||
 | 
					                    (25, "storage path is"),
 | 
				
			||||||
 | 
					                    (26, "has correspondent in"),
 | 
				
			||||||
 | 
					                    (27, "does not have correspondent in"),
 | 
				
			||||||
 | 
					                    (28, "has document type in"),
 | 
				
			||||||
 | 
					                    (29, "does not have document type in"),
 | 
				
			||||||
 | 
					                    (30, "has storage path in"),
 | 
				
			||||||
 | 
					                    (31, "does not have storage path in"),
 | 
				
			||||||
 | 
					                    (32, "owner is"),
 | 
				
			||||||
 | 
					                    (33, "has owner in"),
 | 
				
			||||||
 | 
					                    (34, "does not have owner"),
 | 
				
			||||||
 | 
					                    (35, "does not have owner in"),
 | 
				
			||||||
 | 
					                    (36, "has custom field value"),
 | 
				
			||||||
 | 
					                    (37, "is shared by me"),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                verbose_name="rule type",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -455,6 +455,8 @@ class SavedViewFilterRule(models.Model):
 | 
				
			|||||||
        (33, _("has owner in")),
 | 
					        (33, _("has owner in")),
 | 
				
			||||||
        (34, _("does not have owner")),
 | 
					        (34, _("does not have owner")),
 | 
				
			||||||
        (35, _("does not have owner in")),
 | 
					        (35, _("does not have owner in")),
 | 
				
			||||||
 | 
					        (36, _("has custom field value")),
 | 
				
			||||||
 | 
					        (37, _("is shared by me")),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    saved_view = models.ForeignKey(
 | 
					    saved_view = models.ForeignKey(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ from celery import states
 | 
				
			|||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.contrib.auth.models import Group
 | 
					from django.contrib.auth.models import Group
 | 
				
			||||||
from django.contrib.auth.models import User
 | 
					from django.contrib.auth.models import User
 | 
				
			||||||
 | 
					from django.contrib.contenttypes.models import ContentType
 | 
				
			||||||
from django.core.validators import URLValidator
 | 
					from django.core.validators import URLValidator
 | 
				
			||||||
from django.utils.crypto import get_random_string
 | 
					from django.utils.crypto import get_random_string
 | 
				
			||||||
from django.utils.text import slugify
 | 
					from django.utils.text import slugify
 | 
				
			||||||
@@ -15,6 +16,8 @@ from django.utils.translation import gettext as _
 | 
				
			|||||||
from drf_writable_nested.serializers import NestedUpdateMixin
 | 
					from drf_writable_nested.serializers import NestedUpdateMixin
 | 
				
			||||||
from guardian.core import ObjectPermissionChecker
 | 
					from guardian.core import ObjectPermissionChecker
 | 
				
			||||||
from guardian.shortcuts import get_users_with_perms
 | 
					from guardian.shortcuts import get_users_with_perms
 | 
				
			||||||
 | 
					from guardian.utils import get_group_obj_perms_model
 | 
				
			||||||
 | 
					from guardian.utils import get_user_obj_perms_model
 | 
				
			||||||
from rest_framework import fields
 | 
					from rest_framework import fields
 | 
				
			||||||
from rest_framework import serializers
 | 
					from rest_framework import serializers
 | 
				
			||||||
from rest_framework.fields import SerializerMethodField
 | 
					from rest_framework.fields import SerializerMethodField
 | 
				
			||||||
@@ -160,6 +163,7 @@ class OwnedObjectSerializer(serializers.ModelSerializer, SetPermissionsMixin):
 | 
				
			|||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if full_perms:
 | 
					            if full_perms:
 | 
				
			||||||
                self.fields.pop("user_can_change")
 | 
					                self.fields.pop("user_can_change")
 | 
				
			||||||
 | 
					                self.fields.pop("is_shared_by_requester")
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                self.fields.pop("permissions")
 | 
					                self.fields.pop("permissions")
 | 
				
			||||||
        except KeyError:
 | 
					        except KeyError:
 | 
				
			||||||
@@ -205,8 +209,26 @@ class OwnedObjectSerializer(serializers.ModelSerializer, SetPermissionsMixin):
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_is_shared_by_requester(self, obj: Document):
 | 
				
			||||||
 | 
					        ctype = ContentType.objects.get_for_model(obj)
 | 
				
			||||||
 | 
					        UserObjectPermission = get_user_obj_perms_model()
 | 
				
			||||||
 | 
					        GroupObjectPermission = get_group_obj_perms_model()
 | 
				
			||||||
 | 
					        return obj.owner == self.user and (
 | 
				
			||||||
 | 
					            UserObjectPermission.objects.filter(
 | 
				
			||||||
 | 
					                content_type=ctype,
 | 
				
			||||||
 | 
					                object_pk=obj.pk,
 | 
				
			||||||
 | 
					            ).count()
 | 
				
			||||||
 | 
					            > 0
 | 
				
			||||||
 | 
					            or GroupObjectPermission.objects.filter(
 | 
				
			||||||
 | 
					                content_type=ctype,
 | 
				
			||||||
 | 
					                object_pk=obj.pk,
 | 
				
			||||||
 | 
					            ).count()
 | 
				
			||||||
 | 
					            > 0
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    permissions = SerializerMethodField(read_only=True)
 | 
					    permissions = SerializerMethodField(read_only=True)
 | 
				
			||||||
    user_can_change = SerializerMethodField(read_only=True)
 | 
					    user_can_change = SerializerMethodField(read_only=True)
 | 
				
			||||||
 | 
					    is_shared_by_requester = SerializerMethodField(read_only=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    set_permissions = serializers.DictField(
 | 
					    set_permissions = serializers.DictField(
 | 
				
			||||||
        label="Set permissions",
 | 
					        label="Set permissions",
 | 
				
			||||||
@@ -556,6 +578,7 @@ class DocumentSerializer(
 | 
				
			|||||||
            "owner",
 | 
					            "owner",
 | 
				
			||||||
            "permissions",
 | 
					            "permissions",
 | 
				
			||||||
            "user_can_change",
 | 
					            "user_can_change",
 | 
				
			||||||
 | 
					            "is_shared_by_requester",
 | 
				
			||||||
            "set_permissions",
 | 
					            "set_permissions",
 | 
				
			||||||
            "notes",
 | 
					            "notes",
 | 
				
			||||||
            "custom_fields",
 | 
					            "custom_fields",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -594,7 +594,7 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
 | 
				
			|||||||
        results = response.data["results"]
 | 
					        results = response.data["results"]
 | 
				
			||||||
        self.assertEqual(len(results), 0)
 | 
					        self.assertEqual(len(results), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_document_owner_filters(self):
 | 
					    def test_document_permissions_filters(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        GIVEN:
 | 
					        GIVEN:
 | 
				
			||||||
            - Documents with owners, with and without granted permissions
 | 
					            - Documents with owners, with and without granted permissions
 | 
				
			||||||
@@ -686,6 +686,18 @@ class TestDocumentApi(DirectoriesMixin, DocumentConsumeDelayMixin, APITestCase):
 | 
				
			|||||||
            [u1_doc1.id, u1_doc2.id, u2_doc2.id],
 | 
					            [u1_doc1.id, u1_doc2.id, u2_doc2.id],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        assign_perm("view_document", u2, u1_doc1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Will show only documents shared by user
 | 
				
			||||||
 | 
					        response = self.client.get(f"/api/documents/?shared_by__id={u1.id}")
 | 
				
			||||||
 | 
					        self.assertEqual(response.status_code, status.HTTP_200_OK)
 | 
				
			||||||
 | 
					        results = response.data["results"]
 | 
				
			||||||
 | 
					        self.assertEqual(len(results), 1)
 | 
				
			||||||
 | 
					        self.assertCountEqual(
 | 
				
			||||||
 | 
					            [results[0]["id"]],
 | 
				
			||||||
 | 
					            [u1_doc1.id],
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_pagination_all(self):
 | 
					    def test_pagination_all(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        GIVEN:
 | 
					        GIVEN:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -408,10 +408,17 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
 | 
				
			|||||||
            checksum="3",
 | 
					            checksum="3",
 | 
				
			||||||
            owner=user2,
 | 
					            owner=user2,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        doc4 = Document.objects.create(
 | 
				
			||||||
 | 
					            title="Test4",
 | 
				
			||||||
 | 
					            content="content 4",
 | 
				
			||||||
 | 
					            checksum="4",
 | 
				
			||||||
 | 
					            owner=user1,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assign_perm("view_document", user1, doc2)
 | 
					        assign_perm("view_document", user1, doc2)
 | 
				
			||||||
        assign_perm("view_document", user1, doc3)
 | 
					        assign_perm("view_document", user1, doc3)
 | 
				
			||||||
        assign_perm("change_document", user1, doc3)
 | 
					        assign_perm("change_document", user1, doc3)
 | 
				
			||||||
 | 
					        assign_perm("view_document", user2, doc4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.client.force_authenticate(user1)
 | 
					        self.client.force_authenticate(user1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -426,9 +433,11 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.assertNotIn("permissions", resp_data["results"][0])
 | 
					        self.assertNotIn("permissions", resp_data["results"][0])
 | 
				
			||||||
        self.assertIn("user_can_change", resp_data["results"][0])
 | 
					        self.assertIn("user_can_change", resp_data["results"][0])
 | 
				
			||||||
        self.assertEqual(resp_data["results"][0]["user_can_change"], True)  # doc1
 | 
					        self.assertTrue(resp_data["results"][0]["user_can_change"])  # doc1
 | 
				
			||||||
        self.assertEqual(resp_data["results"][1]["user_can_change"], False)  # doc2
 | 
					        self.assertFalse(resp_data["results"][0]["is_shared_by_requester"])  # doc1
 | 
				
			||||||
        self.assertEqual(resp_data["results"][2]["user_can_change"], True)  # doc3
 | 
					        self.assertFalse(resp_data["results"][1]["user_can_change"])  # doc2
 | 
				
			||||||
 | 
					        self.assertTrue(resp_data["results"][2]["user_can_change"])  # doc3
 | 
				
			||||||
 | 
					        self.assertTrue(resp_data["results"][3]["is_shared_by_requester"])  # doc4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        response = self.client.get(
 | 
					        response = self.client.get(
 | 
				
			||||||
            "/api/documents/?full_perms=true",
 | 
					            "/api/documents/?full_perms=true",
 | 
				
			||||||
@@ -441,6 +450,7 @@ class TestApiAuth(DirectoriesMixin, APITestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.assertIn("permissions", resp_data["results"][0])
 | 
					        self.assertIn("permissions", resp_data["results"][0])
 | 
				
			||||||
        self.assertNotIn("user_can_change", resp_data["results"][0])
 | 
					        self.assertNotIn("user_can_change", resp_data["results"][0])
 | 
				
			||||||
 | 
					        self.assertNotIn("is_shared_by_requester", resp_data["results"][0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestApiUser(DirectoriesMixin, APITestCase):
 | 
					class TestApiUser(DirectoriesMixin, APITestCase):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -968,7 +968,7 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
 | 
				
			|||||||
        u1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
 | 
					        u1.user_permissions.add(*Permission.objects.filter(codename="view_document"))
 | 
				
			||||||
        u2.user_permissions.add(*Permission.objects.filter(codename="view_document"))
 | 
					        u2.user_permissions.add(*Permission.objects.filter(codename="view_document"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Document.objects.create(checksum="1", content="test 1", owner=u1)
 | 
					        d1 = Document.objects.create(checksum="1", content="test 1", owner=u1)
 | 
				
			||||||
        d2 = Document.objects.create(checksum="2", content="test 2", owner=u2)
 | 
					        d2 = Document.objects.create(checksum="2", content="test 2", owner=u2)
 | 
				
			||||||
        d3 = Document.objects.create(checksum="3", content="test 3", owner=u2)
 | 
					        d3 = Document.objects.create(checksum="3", content="test 3", owner=u2)
 | 
				
			||||||
        Document.objects.create(checksum="4", content="test 4")
 | 
					        Document.objects.create(checksum="4", content="test 4")
 | 
				
			||||||
@@ -993,9 +993,10 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        assign_perm("view_document", u1, d2)
 | 
					        assign_perm("view_document", u1, d2)
 | 
				
			||||||
        assign_perm("view_document", u1, d3)
 | 
					        assign_perm("view_document", u1, d3)
 | 
				
			||||||
 | 
					        assign_perm("view_document", u2, d1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with AsyncWriter(index.open_index()) as writer:
 | 
					        with AsyncWriter(index.open_index()) as writer:
 | 
				
			||||||
            for doc in [d2, d3]:
 | 
					            for doc in [d1, d2, d3]:
 | 
				
			||||||
                index.update_document(writer, doc)
 | 
					                index.update_document(writer, doc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.client.force_authenticate(user=u1)
 | 
					        self.client.force_authenticate(user=u1)
 | 
				
			||||||
@@ -1011,6 +1012,8 @@ class TestDocumentSearchApi(DirectoriesMixin, APITestCase):
 | 
				
			|||||||
        self.assertEqual(r.data["count"], 1)
 | 
					        self.assertEqual(r.data["count"], 1)
 | 
				
			||||||
        r = self.client.get("/api/documents/?query=test&owner__isnull=true")
 | 
					        r = self.client.get("/api/documents/?query=test&owner__isnull=true")
 | 
				
			||||||
        self.assertEqual(r.data["count"], 1)
 | 
					        self.assertEqual(r.data["count"], 1)
 | 
				
			||||||
 | 
					        r = self.client.get(f"/api/documents/?query=test&shared_by__id={u1.id}")
 | 
				
			||||||
 | 
					        self.assertEqual(r.data["count"], 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_search_sorting(self):
 | 
					    def test_search_sorting(self):
 | 
				
			||||||
        u1 = User.objects.create_user("user1")
 | 
					        u1 = User.objects.create_user("user1")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ msgid ""
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: paperless-ngx\n"
 | 
					"Project-Id-Version: paperless-ngx\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: \n"
 | 
					"Report-Msgid-Bugs-To: \n"
 | 
				
			||||||
"POT-Creation-Date: 2023-12-05 08:26-0800\n"
 | 
					"POT-Creation-Date: 2023-12-09 10:53-0800\n"
 | 
				
			||||||
"PO-Revision-Date: 2022-02-17 04:17\n"
 | 
					"PO-Revision-Date: 2022-02-17 04:17\n"
 | 
				
			||||||
"Last-Translator: \n"
 | 
					"Last-Translator: \n"
 | 
				
			||||||
"Language-Team: English\n"
 | 
					"Language-Team: English\n"
 | 
				
			||||||
@@ -21,7 +21,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Documents"
 | 
					msgid "Documents"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:36 documents/models.py:734
 | 
					#: documents/models.py:36 documents/models.py:736
 | 
				
			||||||
msgid "owner"
 | 
					msgid "owner"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,7 +53,7 @@ msgstr ""
 | 
				
			|||||||
msgid "Automatic"
 | 
					msgid "Automatic"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:62 documents/models.py:402 documents/models.py:895
 | 
					#: documents/models.py:62 documents/models.py:402 documents/models.py:897
 | 
				
			||||||
#: paperless_mail/models.py:18 paperless_mail/models.py:93
 | 
					#: paperless_mail/models.py:18 paperless_mail/models.py:93
 | 
				
			||||||
msgid "name"
 | 
					msgid "name"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
@@ -132,7 +132,7 @@ msgstr ""
 | 
				
			|||||||
msgid "title"
 | 
					msgid "title"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:171 documents/models.py:648
 | 
					#: documents/models.py:171 documents/models.py:650
 | 
				
			||||||
msgid "content"
 | 
					msgid "content"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -162,8 +162,8 @@ msgstr ""
 | 
				
			|||||||
msgid "The checksum of the archived document."
 | 
					msgid "The checksum of the archived document."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:205 documents/models.py:385 documents/models.py:654
 | 
					#: documents/models.py:205 documents/models.py:385 documents/models.py:656
 | 
				
			||||||
#: documents/models.py:692 documents/models.py:762 documents/models.py:799
 | 
					#: documents/models.py:694 documents/models.py:764 documents/models.py:801
 | 
				
			||||||
msgid "created"
 | 
					msgid "created"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -211,7 +211,7 @@ msgstr ""
 | 
				
			|||||||
msgid "The position of this document in your physical document archive."
 | 
					msgid "The position of this document in your physical document archive."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:279 documents/models.py:665 documents/models.py:719
 | 
					#: documents/models.py:279 documents/models.py:667 documents/models.py:721
 | 
				
			||||||
msgid "document"
 | 
					msgid "document"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -259,7 +259,7 @@ msgstr ""
 | 
				
			|||||||
msgid "logs"
 | 
					msgid "logs"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:399 documents/models.py:464
 | 
					#: documents/models.py:399 documents/models.py:466
 | 
				
			||||||
msgid "saved view"
 | 
					msgid "saved view"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -427,298 +427,306 @@ msgstr ""
 | 
				
			|||||||
msgid "does not have owner in"
 | 
					msgid "does not have owner in"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:467
 | 
					#: documents/models.py:458
 | 
				
			||||||
msgid "rule type"
 | 
					msgid "has custom field value"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: documents/models.py:459
 | 
				
			||||||
 | 
					msgid "is shared by me"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:469
 | 
					#: documents/models.py:469
 | 
				
			||||||
 | 
					msgid "rule type"
 | 
				
			||||||
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: documents/models.py:471
 | 
				
			||||||
msgid "value"
 | 
					msgid "value"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:472
 | 
					#: documents/models.py:474
 | 
				
			||||||
msgid "filter rule"
 | 
					msgid "filter rule"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:473
 | 
					#: documents/models.py:475
 | 
				
			||||||
msgid "filter rules"
 | 
					msgid "filter rules"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:584
 | 
					#: documents/models.py:586
 | 
				
			||||||
msgid "Task ID"
 | 
					msgid "Task ID"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:585
 | 
					#: documents/models.py:587
 | 
				
			||||||
msgid "Celery ID for the Task that was run"
 | 
					msgid "Celery ID for the Task that was run"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:590
 | 
					#: documents/models.py:592
 | 
				
			||||||
msgid "Acknowledged"
 | 
					msgid "Acknowledged"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:591
 | 
					#: documents/models.py:593
 | 
				
			||||||
msgid "If the task is acknowledged via the frontend or API"
 | 
					msgid "If the task is acknowledged via the frontend or API"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:597
 | 
					#: documents/models.py:599
 | 
				
			||||||
msgid "Task Filename"
 | 
					msgid "Task Filename"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:598
 | 
					#: documents/models.py:600
 | 
				
			||||||
msgid "Name of the file which the Task was run for"
 | 
					msgid "Name of the file which the Task was run for"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:604
 | 
					#: documents/models.py:606
 | 
				
			||||||
msgid "Task Name"
 | 
					msgid "Task Name"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:605
 | 
					#: documents/models.py:607
 | 
				
			||||||
msgid "Name of the Task which was run"
 | 
					msgid "Name of the Task which was run"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:612
 | 
					#: documents/models.py:614
 | 
				
			||||||
msgid "Task State"
 | 
					msgid "Task State"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:613
 | 
					#: documents/models.py:615
 | 
				
			||||||
msgid "Current state of the task being run"
 | 
					msgid "Current state of the task being run"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:618
 | 
					#: documents/models.py:620
 | 
				
			||||||
msgid "Created DateTime"
 | 
					msgid "Created DateTime"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:619
 | 
					#: documents/models.py:621
 | 
				
			||||||
msgid "Datetime field when the task result was created in UTC"
 | 
					msgid "Datetime field when the task result was created in UTC"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:624
 | 
					#: documents/models.py:626
 | 
				
			||||||
msgid "Started DateTime"
 | 
					msgid "Started DateTime"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:625
 | 
					#: documents/models.py:627
 | 
				
			||||||
msgid "Datetime field when the task was started in UTC"
 | 
					msgid "Datetime field when the task was started in UTC"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:630
 | 
					#: documents/models.py:632
 | 
				
			||||||
msgid "Completed DateTime"
 | 
					msgid "Completed DateTime"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:631
 | 
					#: documents/models.py:633
 | 
				
			||||||
msgid "Datetime field when the task was completed in UTC"
 | 
					msgid "Datetime field when the task was completed in UTC"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:636
 | 
					#: documents/models.py:638
 | 
				
			||||||
msgid "Result Data"
 | 
					msgid "Result Data"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:638
 | 
					#: documents/models.py:640
 | 
				
			||||||
msgid "The data returned by the task"
 | 
					msgid "The data returned by the task"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:650
 | 
					#: documents/models.py:652
 | 
				
			||||||
msgid "Note for the document"
 | 
					msgid "Note for the document"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:674
 | 
					#: documents/models.py:676
 | 
				
			||||||
msgid "user"
 | 
					msgid "user"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:679
 | 
					#: documents/models.py:681
 | 
				
			||||||
msgid "note"
 | 
					msgid "note"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:680
 | 
					#: documents/models.py:682
 | 
				
			||||||
msgid "notes"
 | 
					msgid "notes"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:688
 | 
					#: documents/models.py:690
 | 
				
			||||||
msgid "Archive"
 | 
					msgid "Archive"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:689
 | 
					#: documents/models.py:691
 | 
				
			||||||
msgid "Original"
 | 
					msgid "Original"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:700
 | 
					#: documents/models.py:702
 | 
				
			||||||
msgid "expiration"
 | 
					msgid "expiration"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:707
 | 
					#: documents/models.py:709
 | 
				
			||||||
msgid "slug"
 | 
					msgid "slug"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:739
 | 
					#: documents/models.py:741
 | 
				
			||||||
msgid "share link"
 | 
					msgid "share link"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:740
 | 
					#: documents/models.py:742
 | 
				
			||||||
msgid "share links"
 | 
					msgid "share links"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:752
 | 
					#: documents/models.py:754
 | 
				
			||||||
msgid "String"
 | 
					msgid "String"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:753
 | 
					#: documents/models.py:755
 | 
				
			||||||
msgid "URL"
 | 
					msgid "URL"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:754
 | 
					#: documents/models.py:756
 | 
				
			||||||
msgid "Date"
 | 
					msgid "Date"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:755
 | 
					#: documents/models.py:757
 | 
				
			||||||
msgid "Boolean"
 | 
					msgid "Boolean"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:756
 | 
					#: documents/models.py:758
 | 
				
			||||||
msgid "Integer"
 | 
					msgid "Integer"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:757
 | 
					#: documents/models.py:759
 | 
				
			||||||
msgid "Float"
 | 
					msgid "Float"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:758
 | 
					#: documents/models.py:760
 | 
				
			||||||
msgid "Monetary"
 | 
					msgid "Monetary"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:759
 | 
					#: documents/models.py:761
 | 
				
			||||||
msgid "Document Link"
 | 
					msgid "Document Link"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:771
 | 
					#: documents/models.py:773
 | 
				
			||||||
msgid "data type"
 | 
					msgid "data type"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:779
 | 
					#: documents/models.py:781
 | 
				
			||||||
msgid "custom field"
 | 
					msgid "custom field"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:780
 | 
					#: documents/models.py:782
 | 
				
			||||||
msgid "custom fields"
 | 
					msgid "custom fields"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:842
 | 
					#: documents/models.py:844
 | 
				
			||||||
msgid "custom field instance"
 | 
					msgid "custom field instance"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:843
 | 
					#: documents/models.py:845
 | 
				
			||||||
msgid "custom field instances"
 | 
					msgid "custom field instances"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:891
 | 
					#: documents/models.py:893
 | 
				
			||||||
msgid "Consume Folder"
 | 
					msgid "Consume Folder"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:892
 | 
					#: documents/models.py:894
 | 
				
			||||||
msgid "Api Upload"
 | 
					msgid "Api Upload"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:893
 | 
					#: documents/models.py:895
 | 
				
			||||||
msgid "Mail Fetch"
 | 
					msgid "Mail Fetch"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:897 paperless_mail/models.py:95
 | 
					#: documents/models.py:899 paperless_mail/models.py:95
 | 
				
			||||||
msgid "order"
 | 
					msgid "order"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:906
 | 
					#: documents/models.py:908
 | 
				
			||||||
msgid "filter path"
 | 
					msgid "filter path"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:911
 | 
					#: documents/models.py:913
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Only consume documents with a path that matches this if specified. Wildcards "
 | 
					"Only consume documents with a path that matches this if specified. Wildcards "
 | 
				
			||||||
"specified as * are allowed. Case insensitive."
 | 
					"specified as * are allowed. Case insensitive."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:918
 | 
					#: documents/models.py:920
 | 
				
			||||||
msgid "filter filename"
 | 
					msgid "filter filename"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:923 paperless_mail/models.py:148
 | 
					#: documents/models.py:925 paperless_mail/models.py:148
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Only consume documents which entirely match this filename if specified. "
 | 
					"Only consume documents which entirely match this filename if specified. "
 | 
				
			||||||
"Wildcards such as *.pdf or *invoice* are allowed. Case insensitive."
 | 
					"Wildcards such as *.pdf or *invoice* are allowed. Case insensitive."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:934
 | 
					#: documents/models.py:936
 | 
				
			||||||
msgid "filter documents from this mail rule"
 | 
					msgid "filter documents from this mail rule"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:938
 | 
					#: documents/models.py:940
 | 
				
			||||||
msgid "assign title"
 | 
					msgid "assign title"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:943
 | 
					#: documents/models.py:945
 | 
				
			||||||
msgid ""
 | 
					msgid ""
 | 
				
			||||||
"Assign a document title, can include some placeholders, see documentation."
 | 
					"Assign a document title, can include some placeholders, see documentation."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:951 paperless_mail/models.py:216
 | 
					#: documents/models.py:953 paperless_mail/models.py:216
 | 
				
			||||||
msgid "assign this tag"
 | 
					msgid "assign this tag"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:959 paperless_mail/models.py:224
 | 
					#: documents/models.py:961 paperless_mail/models.py:224
 | 
				
			||||||
msgid "assign this document type"
 | 
					msgid "assign this document type"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:967 paperless_mail/models.py:238
 | 
					#: documents/models.py:969 paperless_mail/models.py:238
 | 
				
			||||||
msgid "assign this correspondent"
 | 
					msgid "assign this correspondent"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:975
 | 
					#: documents/models.py:977
 | 
				
			||||||
msgid "assign this storage path"
 | 
					msgid "assign this storage path"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:984
 | 
					#: documents/models.py:986
 | 
				
			||||||
msgid "assign this owner"
 | 
					msgid "assign this owner"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:991
 | 
					#: documents/models.py:993
 | 
				
			||||||
msgid "grant view permissions to these users"
 | 
					msgid "grant view permissions to these users"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:998
 | 
					#: documents/models.py:1000
 | 
				
			||||||
msgid "grant view permissions to these groups"
 | 
					msgid "grant view permissions to these groups"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:1005
 | 
					#: documents/models.py:1007
 | 
				
			||||||
msgid "grant change permissions to these users"
 | 
					msgid "grant change permissions to these users"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:1012
 | 
					#: documents/models.py:1014
 | 
				
			||||||
msgid "grant change permissions to these groups"
 | 
					msgid "grant change permissions to these groups"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:1019
 | 
					#: documents/models.py:1021
 | 
				
			||||||
msgid "assign these custom fields"
 | 
					msgid "assign these custom fields"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:1023
 | 
					#: documents/models.py:1025
 | 
				
			||||||
msgid "consumption template"
 | 
					msgid "consumption template"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/models.py:1024
 | 
					#: documents/models.py:1026
 | 
				
			||||||
msgid "consumption templates"
 | 
					msgid "consumption templates"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/serialisers.py:102
 | 
					#: documents/serialisers.py:105
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid "Invalid regular expression: %(error)s"
 | 
					msgid "Invalid regular expression: %(error)s"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/serialisers.py:377
 | 
					#: documents/serialisers.py:399
 | 
				
			||||||
msgid "Invalid color."
 | 
					msgid "Invalid color."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/serialisers.py:842
 | 
					#: documents/serialisers.py:865
 | 
				
			||||||
#, python-format
 | 
					#, python-format
 | 
				
			||||||
msgid "File type %(type)s not supported"
 | 
					msgid "File type %(type)s not supported"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: documents/serialisers.py:939
 | 
					#: documents/serialisers.py:962
 | 
				
			||||||
msgid "Invalid variable detected."
 | 
					msgid "Invalid variable detected."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user