mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Merge branch 'dev'
This commit is contained in:
		
							
								
								
									
										46
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -20,7 +20,7 @@ jobs: | ||||
|         name: Set up Python | ||||
|         uses: actions/setup-python@v2 | ||||
|         with: | ||||
|           python-version: 3.8 | ||||
|           python-version: 3.7 | ||||
|       - | ||||
|         name: Get pip cache dir | ||||
|         id: pip-cache | ||||
| @@ -49,6 +49,39 @@ jobs: | ||||
|           name: documentation | ||||
|           path: docs/_build/html/ | ||||
|  | ||||
|   codestyle: | ||||
|     runs-on: ubuntu-20.04 | ||||
|     steps: | ||||
|       - | ||||
|         name: Checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - | ||||
|         name: Set up Python | ||||
|         uses: actions/setup-python@v2 | ||||
|         with: | ||||
|           python-version: 3.7 | ||||
|       - | ||||
|         name: Get pip cache dir | ||||
|         id: pip-cache | ||||
|         run: | | ||||
|           echo "::set-output name=dir::$(pip cache dir)" | ||||
|       - | ||||
|         name: Persistent Github pip cache | ||||
|         uses: actions/cache@v2 | ||||
|         with: | ||||
|           path: ${{ steps.pip-cache.outputs.dir }} | ||||
|           key: ${{ runner.os }}-pip${{ matrix.python-version }} | ||||
|       - | ||||
|         name: Install dependencies | ||||
|         run: | | ||||
|           pip install --upgrade pipenv | ||||
|           pipenv install --system --dev --ignore-pipfile | ||||
|       - | ||||
|         name: Codestyle | ||||
|         run: | | ||||
|           cd src/ | ||||
|           pycodestyle | ||||
|  | ||||
|   tests: | ||||
|     runs-on: ubuntu-20.04 | ||||
|     strategy: | ||||
| @@ -76,7 +109,7 @@ jobs: | ||||
|           path: ${{ steps.pip-cache.outputs.dir }} | ||||
|           key: ${{ runner.os }}-pip${{ matrix.python-version }} | ||||
|       - | ||||
|         name: Prepare tests | ||||
|         name: Install dependencies | ||||
|         run: | | ||||
|           sudo apt-get update -qq | ||||
|           sudo apt-get install -qq --no-install-recommends unpaper tesseract-ocr imagemagick ghostscript optipng | ||||
| @@ -87,11 +120,6 @@ jobs: | ||||
|         run: | | ||||
|           cd src/ | ||||
|           pytest | ||||
|       - | ||||
|         name: Codestyle | ||||
|         run: | | ||||
|           cd src/ | ||||
|           pycodestyle | ||||
|       - | ||||
|         name: Publish coverage results | ||||
|         if: matrix.python-version == '3.8' | ||||
| @@ -130,7 +158,7 @@ jobs: | ||||
|         path: src/documents/static/frontend/ | ||||
|  | ||||
|   build-release: | ||||
|     needs: [frontend, documentation, tests] | ||||
|     needs: [frontend, documentation, tests, codestyle] | ||||
|     runs-on: ubuntu-20.04 | ||||
|     steps: | ||||
|       - | ||||
| @@ -240,7 +268,7 @@ jobs: | ||||
|   build-docker-image: | ||||
|     if: github.event_name == 'push' && (startsWith(github.ref, 'refs/heads/feature-') || github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/ng-')) | ||||
|     runs-on: ubuntu-latest | ||||
|     needs: [frontend, tests] | ||||
|     needs: [frontend, tests, codestyle] | ||||
|     steps: | ||||
|       - | ||||
|         name: Prepare | ||||
|   | ||||
| @@ -77,9 +77,9 @@ The documentation for Paperless-ng is available on [ReadTheDocs](https://paperle | ||||
|  | ||||
| # Translation | ||||
|  | ||||
| Paperless is currently available in English, German, Dutch and French. Translation is coordinated at transifex: https://www.transifex.com/paperless/paperless-ng | ||||
| Paperless is currently available in English, German, Dutch, French, and Portuguese. | ||||
|  | ||||
| If you want to see paperless in your own language, request that language at transifex and you can start translating after I approve the language. | ||||
| There's an active translation project at transifex! If you want to help out by translating paperless into your language, please head over to https://github.com/jonaswinkler/paperless-ng/issues/212 for details. | ||||
|  | ||||
| # Feature Requests | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,19 @@ | ||||
| Changelog | ||||
| ********* | ||||
|  | ||||
| paperless-ng 1.2.1 | ||||
| ################## | ||||
|  | ||||
| * `Rodrigo Avelino <https://github.com/rodavelino>`_ translated Paperless into Portuguese (Brazil)! | ||||
|  | ||||
| * The date input fields now respect the currently selected date format. | ||||
|  | ||||
| * Added a fancy icon when adding paperless to the home screen on iOS devices. Thanks to `Joel Nordell <https://github.com/joelnordell>`_. | ||||
|  | ||||
| * When using regular expression matching, the regular expression is now validated before saving the tag/correspondent/type. | ||||
|  | ||||
| * Regression fix: Dates on the front end did not respect date locale settings in some cases. | ||||
|  | ||||
| paperless-ng 1.2.0 | ||||
| ################## | ||||
|  | ||||
|   | ||||
| @@ -19,7 +19,8 @@ | ||||
| 					"de": "src/locale/messages.de.xlf", | ||||
| 					"nl-NL": "src/locale/messages.nl_NL.xlf", | ||||
| 					"fr": "src/locale/messages.fr.xlf", | ||||
| 					"en-GB": "src/locale/messages.en_GB.xlf" | ||||
| 					"en-GB": "src/locale/messages.en_GB.xlf", | ||||
| 					"pt-BR": "src/locale/messages.pt_BR.xlf" | ||||
| 				} | ||||
| 			}, | ||||
| 			"architect": { | ||||
| @@ -36,6 +37,7 @@ | ||||
| 						"aot": true, | ||||
| 						"assets": [ | ||||
| 							"src/favicon.ico", | ||||
| 							"src/apple-touch-icon.png", | ||||
| 							"src/assets", | ||||
| 							"src/manifest.webmanifest", { | ||||
| 								"glob": "pdf.worker.min.js", | ||||
| @@ -112,6 +114,7 @@ | ||||
| 						"karmaConfig": "karma.conf.js", | ||||
| 						"assets": [ | ||||
| 							"src/favicon.ico", | ||||
| 							"src/apple-touch-icon.png", | ||||
| 							"src/assets", | ||||
| 							"src/manifest.webmanifest" | ||||
| 						], | ||||
|   | ||||
| @@ -531,28 +531,21 @@ | ||||
|         <source>Use system language</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">91</context> | ||||
|           <context context-type="linenumber">92</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="7729897675462249787" datatype="html"> | ||||
|         <source>Use date format of display language</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">96</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="4912706592792948707" datatype="html"> | ||||
|         <source>ISO 8601</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">97</context> | ||||
|           <context context-type="linenumber">98</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="8488620293789898901" datatype="html"> | ||||
|         <source>Error while storing settings on server: <x id="PH" equiv-text="JSON.stringify(error.error)"/></source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">114</context> | ||||
|           <context context-type="linenumber">115</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="121cc5391cd2a5115bc2b3160379ee5b36cd7716" datatype="html"> | ||||
| @@ -1605,6 +1598,13 @@ | ||||
|           <context context-type="linenumber">21</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="d6529debfc1613db22d6fa096ebfeb8a85fa739d" datatype="html"> | ||||
|         <source>Invalid date.</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context> | ||||
|           <context context-type="linenumber">13</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="2807800733729323332" datatype="html"> | ||||
|         <source>Yes</source> | ||||
|         <context-group purpose="location"> | ||||
| @@ -1630,35 +1630,49 @@ | ||||
|         <source>English (US)</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">82</context> | ||||
|           <context context-type="linenumber">88</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="6987083569809053351" datatype="html"> | ||||
|         <source>English (GB)</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">83</context> | ||||
|           <context context-type="linenumber">89</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="1858110241312746425" datatype="html"> | ||||
|         <source>German</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">84</context> | ||||
|           <context context-type="linenumber">90</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="3071065188816255493" datatype="html"> | ||||
|         <source>Dutch</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">85</context> | ||||
|           <context context-type="linenumber">91</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="7633754075223722162" datatype="html"> | ||||
|         <source>French</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">86</context> | ||||
|           <context context-type="linenumber">92</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="9184513005098760425" datatype="html"> | ||||
|         <source>Portuguese (Brazil)</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">93</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="4912706592792948707" datatype="html"> | ||||
|         <source>ISO 8601</source> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">98</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit id="2119857572761283468" datatype="html"> | ||||
|   | ||||
							
								
								
									
										6
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								src-ui/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -2055,9 +2055,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "@ng-bootstrap/ng-bootstrap": { | ||||
|       "version": "8.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-8.0.0.tgz", | ||||
|       "integrity": "sha512-v77Gfd8xHH+exq0WqIqVRlxbUEHdA/2+RUJenUP2IDTQN9E1rWl7O461/kosr+0XPuxPArHQJxhh/WsCYckcNg==", | ||||
|       "version": "8.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-8.0.4.tgz", | ||||
|       "integrity": "sha512-EdxTwOPOtlvfnwrglPniulmzdnXdXH3lTGaGAY1HrYRvdtGg6wicRvl+BvwVE/3Qik5NPkOWMVghUHpv3evIYg==", | ||||
|       "requires": { | ||||
|         "tslib": "^2.0.0" | ||||
|       } | ||||
|   | ||||
| @@ -20,7 +20,7 @@ | ||||
|     "@angular/platform-browser": "~10.1.5", | ||||
|     "@angular/platform-browser-dynamic": "~10.1.5", | ||||
|     "@angular/router": "~10.1.5", | ||||
|     "@ng-bootstrap/ng-bootstrap": "^8.0.0", | ||||
|     "@ng-bootstrap/ng-bootstrap": "^8.0.4", | ||||
|     "@ng-select/ng-select": "^5.0.9", | ||||
|     "bootstrap": "^4.5.0", | ||||
|     "file-saver": "^2.0.5", | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import { NgModule } from '@angular/core'; | ||||
|  | ||||
| import { AppRoutingModule } from './app-routing.module'; | ||||
| import { AppComponent } from './app.component'; | ||||
| import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; | ||||
| import { NgbDateAdapter, NgbDateParserFormatter, NgbModule } from '@ng-bootstrap/ng-bootstrap'; | ||||
| import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; | ||||
| import { DocumentListComponent } from './components/document-list/document-list.component'; | ||||
| import { DocumentDetailComponent } from './components/document-detail/document-detail.component'; | ||||
| @@ -39,7 +39,6 @@ import { SelectComponent } from './components/common/input/select/select.compone | ||||
| import { CheckComponent } from './components/common/input/check/check.component'; | ||||
| import { SaveViewConfigDialogComponent } from './components/document-list/save-view-config-dialog/save-view-config-dialog.component'; | ||||
| import { InfiniteScrollModule } from 'ngx-infinite-scroll'; | ||||
| import { DateTimeComponent } from './components/common/input/date-time/date-time.component'; | ||||
| import { TagsComponent } from './components/common/input/tags/tags.component'; | ||||
| import { SortableDirective } from './directives/sortable.directive'; | ||||
| import { CookieService } from 'ngx-cookie-service'; | ||||
| @@ -60,15 +59,21 @@ import { NgSelectModule } from '@ng-select/ng-select'; | ||||
| import { NumberComponent } from './components/common/input/number/number.component'; | ||||
| import { SafePipe } from './pipes/safe.pipe'; | ||||
| import { CustomDatePipe } from './pipes/custom-date.pipe'; | ||||
| import { DateComponent } from './components/common/input/date/date.component'; | ||||
| import { ISODateTimeAdapter } from './utils/ngb-iso-date-time-adapter'; | ||||
| import { LocalizedDateParserFormatter } from './utils/ngb-date-parser-formatter'; | ||||
| import { ApiVersionInterceptor } from './interceptors/api-version.interceptor'; | ||||
|  | ||||
| import localeFr from '@angular/common/locales/fr'; | ||||
| import localeNl from '@angular/common/locales/nl'; | ||||
| import localeDe from '@angular/common/locales/de'; | ||||
| import localePt from '@angular/common/locales/pt'; | ||||
| import localeEnGb from '@angular/common/locales/en-GB'; | ||||
|  | ||||
| registerLocaleData(localeFr) | ||||
| registerLocaleData(localeNl) | ||||
| registerLocaleData(localeDe) | ||||
| registerLocaleData(localePt, "pt-BR") | ||||
| registerLocaleData(localeEnGb) | ||||
|  | ||||
| @NgModule({ | ||||
| @@ -104,7 +109,6 @@ registerLocaleData(localeEnGb) | ||||
|     SelectComponent, | ||||
|     CheckComponent, | ||||
|     SaveViewConfigDialogComponent, | ||||
|     DateTimeComponent, | ||||
|     TagsComponent, | ||||
|     SortableDirective, | ||||
|     SavedViewWidgetComponent, | ||||
| @@ -120,7 +124,8 @@ registerLocaleData(localeEnGb) | ||||
|     SelectDialogComponent, | ||||
|     NumberComponent, | ||||
|     SafePipe, | ||||
|     CustomDatePipe | ||||
|     CustomDatePipe, | ||||
|     DateComponent | ||||
|   ], | ||||
|   imports: [ | ||||
|     BrowserModule, | ||||
| @@ -140,9 +145,15 @@ registerLocaleData(localeEnGb) | ||||
|       provide: HTTP_INTERCEPTORS, | ||||
|       useClass: CsrfInterceptor, | ||||
|       multi: true | ||||
|     },{ | ||||
|       provide: HTTP_INTERCEPTORS, | ||||
|       useClass: ApiVersionInterceptor, | ||||
|       multi: true | ||||
|     }, | ||||
|     FilterPipe, | ||||
|     DocumentTitlePipe | ||||
|     DocumentTitlePipe, | ||||
|     {provide: NgbDateAdapter, useClass: ISODateTimeAdapter}, | ||||
|     {provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter} | ||||
|   ], | ||||
|   bootstrap: [AppComponent] | ||||
| }) | ||||
|   | ||||
| @@ -94,7 +94,7 @@ | ||||
|               </svg> {{d.title | documentTitle}} | ||||
|             </a> | ||||
|           </li> | ||||
|           <li class="nav-item w-100" *ngIf="openDocuments.length > 1"> | ||||
|           <li class="nav-item w-100" *ngIf="openDocuments.length >= 1"> | ||||
|             <a class="nav-link text-truncate" [routerLink]="" (click)="closeAll()"> | ||||
|               <svg class="sidebaricon" fill="currentColor"> | ||||
|                 <use xlink:href="assets/bootstrap-icons.svg#x"/> | ||||
|   | ||||
| @@ -20,9 +20,18 @@ | ||||
|           </div> | ||||
|  | ||||
|           <div class="input-group input-group-sm"> | ||||
|             <input type="date" class="form-control" id="date_after" [(ngModel)]="dateAfter" (change)="onChangeDebounce()"> | ||||
|             <input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" | ||||
|                     [(ngModel)]="dateAfter" ngbDatepicker #dateAfterPicker="ngbDatepicker"> | ||||
|             <div class="input-group-append"> | ||||
|               <button class="btn btn-outline-secondary" (click)="dateAfterPicker.toggle()" type="button"> | ||||
|                 <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16"> | ||||
|                   <path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/> | ||||
|                 </svg> | ||||
|               </button> | ||||
|             </div> | ||||
|           </div> | ||||
|  | ||||
|         </div> | ||||
|         <div class="list-group-item d-flex flex-column align-items-start" role="menuitem"> | ||||
|  | ||||
|           <div class="mb-2 d-flex flex-row w-100 justify-content-between small"> | ||||
| @@ -36,9 +45,18 @@ | ||||
|           </div> | ||||
|  | ||||
|           <div class="input-group input-group-sm"> | ||||
|             <input type="date" class="form-control" id="date_before" [(ngModel)]="dateBefore" (change)="onChangeDebounce()"> | ||||
|             <input class="form-control" [placeholder]="datePlaceHolder" (dateSelect)="onChangeDebounce()" (change)="onChangeDebounce()" | ||||
|                     [(ngModel)]="dateBefore" ngbDatepicker #dateBeforePicker="ngbDatepicker"> | ||||
|             <div class="input-group-append"> | ||||
|               <button class="btn btn-outline-secondary" (click)="dateBeforePicker.toggle()" type="button"> | ||||
|                 <svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16"> | ||||
|                   <path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/> | ||||
|                 </svg> | ||||
|               </button> | ||||
|             </div> | ||||
|           </div> | ||||
|            | ||||
|         </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
|   | ||||
| @@ -1,7 +1,10 @@ | ||||
| import { formatDate } from '@angular/common'; | ||||
| import { Component, EventEmitter, Input, Output, OnInit, OnDestroy } from '@angular/core'; | ||||
| import { NgbDateAdapter } from '@ng-bootstrap/ng-bootstrap'; | ||||
| import { Subject, Subscription } from 'rxjs'; | ||||
| import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; | ||||
| import { debounceTime } from 'rxjs/operators'; | ||||
| import { SettingsService } from 'src/app/services/settings.service'; | ||||
| import { ISODateAdapter } from 'src/app/utils/ngb-iso-date-adapter'; | ||||
|  | ||||
| export interface DateSelection { | ||||
|   before?: string | ||||
| @@ -16,10 +19,17 @@ const LAST_YEAR = 3 | ||||
| @Component({ | ||||
|   selector: 'app-date-dropdown', | ||||
|   templateUrl: './date-dropdown.component.html', | ||||
|   styleUrls: ['./date-dropdown.component.scss'] | ||||
|   styleUrls: ['./date-dropdown.component.scss'], | ||||
|   providers: [ | ||||
|     {provide: NgbDateAdapter, useClass: ISODateAdapter}, | ||||
|   ] | ||||
| }) | ||||
| export class DateDropdownComponent implements OnInit, OnDestroy { | ||||
|  | ||||
|   constructor(settings: SettingsService) { | ||||
|     this.datePlaceHolder = settings.getLocalizedDateInputFormat() | ||||
|   } | ||||
|  | ||||
|   quickFilters = [ | ||||
|     {id: LAST_7_DAYS, name: $localize`Last 7 days`}, | ||||
|     {id: LAST_MONTH, name: $localize`Last month`}, | ||||
| @@ -27,6 +37,8 @@ export class DateDropdownComponent implements OnInit, OnDestroy { | ||||
|     {id: LAST_YEAR, name: $localize`Last year`} | ||||
|   ] | ||||
|  | ||||
|   datePlaceHolder: string | ||||
|  | ||||
|   @Input() | ||||
|   dateBefore: string | ||||
|  | ||||
|   | ||||
| @@ -1,13 +0,0 @@ | ||||
| <div class="form-row"> | ||||
|   <div class="form-group col"> | ||||
|       <label for="created_date">{{titleDate}}</label> | ||||
|       <input type="date" class="form-control" id="created_date" [(ngModel)]="dateValue" (change)="dateOrTimeChanged()"> | ||||
|   </div> | ||||
|   <div class="form-group col" *ngIf="titleTime"> | ||||
|       <label for="created_time">{{titleTime}}</label> | ||||
|       <input type="time" class="form-control" id="created_time" [(ngModel)]="timeValue" (change)="dateOrTimeChanged()"> | ||||
|   </div> | ||||
| </div> | ||||
|  | ||||
|  | ||||
| <!-- <small *ngIf="hint" class="form-text text-muted">{{hint}}</small> --> | ||||
| @@ -1,61 +0,0 @@ | ||||
| import { formatDate } from '@angular/common'; | ||||
| import { Component, forwardRef, Input, OnInit } from '@angular/core'; | ||||
| import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; | ||||
|  | ||||
| @Component({ | ||||
|   providers: [{ | ||||
|     provide: NG_VALUE_ACCESSOR, | ||||
|     useExisting: forwardRef(() => DateTimeComponent), | ||||
|     multi: true | ||||
|   }], | ||||
|   selector: 'app-input-date-time', | ||||
|   templateUrl: './date-time.component.html', | ||||
|   styleUrls: ['./date-time.component.scss'] | ||||
| }) | ||||
| export class DateTimeComponent implements OnInit,ControlValueAccessor  { | ||||
|  | ||||
|   constructor() { | ||||
|   } | ||||
|  | ||||
|   onChange = (newValue: any) => {}; | ||||
|    | ||||
|   onTouched = () => {}; | ||||
|  | ||||
|   writeValue(newValue: any): void { | ||||
|     this.dateValue = formatDate(newValue, 'yyyy-MM-dd', "en-US") | ||||
|     this.timeValue = formatDate(newValue, 'HH:mm:ss', 'en-US') | ||||
|   } | ||||
|   registerOnChange(fn: any): void { | ||||
|     this.onChange = fn; | ||||
|   } | ||||
|   registerOnTouched(fn: any): void { | ||||
|     this.onTouched = fn; | ||||
|   } | ||||
|   setDisabledState?(isDisabled: boolean): void { | ||||
|     this.disabled = isDisabled; | ||||
|   } | ||||
|  | ||||
|   @Input() | ||||
|   titleDate: string = "Date" | ||||
|  | ||||
|   @Input() | ||||
|   titleTime: string | ||||
|  | ||||
|   @Input() | ||||
|   disabled: boolean = false | ||||
|  | ||||
|   @Input() | ||||
|   hint: string | ||||
|  | ||||
|   timeValue | ||||
|  | ||||
|   dateValue | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|   } | ||||
|  | ||||
|   dateOrTimeChanged() { | ||||
|     this.onChange(formatDate(this.dateValue + "T" + this.timeValue,"yyyy-MM-ddTHH:mm:ssZZZZZ", "en-us", "UTC")) | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,16 @@ | ||||
| <div class="form-group"> | ||||
|   <label [for]="inputId">{{title}}</label> | ||||
|   <div class="input-group" [class.is-invalid]="error"> | ||||
|     <input class="form-control" [class.is-invalid]="error"  [placeholder]="placeholder" [id]="inputId" (dateSelect)="onChange(value)" (change)="onChange(value)" | ||||
|            name="dp" [(ngModel)]="value" ngbDatepicker #datePicker="ngbDatepicker" #datePickerContent="ngModel"> | ||||
|     <div class="input-group-append"> | ||||
|       <button class="btn btn-outline-secondary calendar" (click)="datePicker.toggle()" type="button"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-calendar" viewBox="0 0 16 16"> | ||||
|           <path d="M3.5 0a.5.5 0 0 1 .5.5V1h8V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM1 4v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4H1z"/> | ||||
|         </svg> | ||||
|       </button> | ||||
|     </div> | ||||
|   </div> | ||||
|   <div class="invalid-feedback" i18n>Invalid date.</div> | ||||
|   <small *ngIf="hint" class="form-text text-muted">{{hint}}</small> | ||||
| </div> | ||||
| @@ -1,20 +1,20 @@ | ||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||||
| 
 | ||||
| import { DateTimeComponent } from './date-time.component'; | ||||
| import { DateComponent } from './date.component'; | ||||
| 
 | ||||
| describe('DateTimeComponent', () => { | ||||
|   let component: DateTimeComponent; | ||||
|   let fixture: ComponentFixture<DateTimeComponent>; | ||||
| describe('DateComponent', () => { | ||||
|   let component: DateComponent; | ||||
|   let fixture: ComponentFixture<DateComponent>; | ||||
| 
 | ||||
|   beforeEach(async () => { | ||||
|     await TestBed.configureTestingModule({ | ||||
|       declarations: [ DateTimeComponent ] | ||||
|       declarations: [ DateComponent ] | ||||
|     }) | ||||
|     .compileComponents(); | ||||
|   }); | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     fixture = TestBed.createComponent(DateTimeComponent); | ||||
|     fixture = TestBed.createComponent(DateComponent); | ||||
|     component = fixture.componentInstance; | ||||
|     fixture.detectChanges(); | ||||
|   }); | ||||
| @@ -0,0 +1,32 @@ | ||||
| import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; | ||||
| import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; | ||||
| import { NgbDateAdapter, NgbDateParserFormatter, NgbDatepickerContent } from '@ng-bootstrap/ng-bootstrap'; | ||||
| import { SettingsService } from 'src/app/services/settings.service'; | ||||
| import { v4 as uuidv4 } from 'uuid'; | ||||
| import { AbstractInputComponent } from '../abstract-input'; | ||||
|  | ||||
|  | ||||
| @Component({ | ||||
|   providers: [{ | ||||
|     provide: NG_VALUE_ACCESSOR, | ||||
|     useExisting: forwardRef(() => DateComponent), | ||||
|     multi: true | ||||
|   }], | ||||
|   selector: 'app-input-date', | ||||
|   templateUrl: './date.component.html', | ||||
|   styleUrls: ['./date.component.scss'] | ||||
| }) | ||||
| export class DateComponent extends AbstractInputComponent<string> implements OnInit { | ||||
|  | ||||
|   constructor(private settings: SettingsService) { | ||||
|     super() | ||||
|   } | ||||
|  | ||||
|   ngOnInit(): void { | ||||
|     super.ngOnInit() | ||||
|     this.placeholder = this.settings.getLocalizedDateInputFormat() | ||||
|   } | ||||
|  | ||||
|   placeholder: string | ||||
|  | ||||
| } | ||||
| @@ -58,7 +58,7 @@ | ||||
|  | ||||
|                         <app-input-text #inputTitle i18n-title title="Title" formControlName="title" [error]="error?.title"></app-input-text> | ||||
|                         <app-input-number i18n-title title="Archive serial number" [error]="error?.archive_serial_number" formControlName='archive_serial_number'></app-input-number> | ||||
|                         <app-input-date-time i18n-titleDate titleDate="Date created" formControlName="created"></app-input-date-time> | ||||
|                         <app-input-date i18n-title title="Date created" formControlName="created" [error]="error?.created"></app-input-date> | ||||
|                         <app-input-select [items]="correspondents" i18n-title title="Correspondent" formControlName="correspondent" [allowNull]="true" | ||||
|                             (createNew)="createCorrespondent()" [suggestions]="suggestions?.correspondents"></app-input-select> | ||||
|                         <app-input-select [items]="documentTypes" i18n-title title="Document type" formControlName="document_type" [allowNull]="true" | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
|   <div class="modal-body"> | ||||
|     <app-input-text i18n-title title="Name" formControlName="name" [error]="error?.name"></app-input-text> | ||||
|     <app-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select> | ||||
|     <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match"></app-input-text> | ||||
|     <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text> | ||||
|     <app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive" novalidate></app-input-check> | ||||
|   </div> | ||||
|   <div class="modal-footer"> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|  | ||||
|       <app-input-text i18n-title title="Name" formControlName="name" [error]="error?.name"></app-input-text> | ||||
|       <app-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select> | ||||
|       <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match"></app-input-text> | ||||
|       <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text> | ||||
|       <app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check> | ||||
|  | ||||
|     </div> | ||||
|   | ||||
| @@ -88,14 +88,15 @@ export class SettingsComponent implements OnInit { | ||||
|   } | ||||
|  | ||||
|   get displayLanguageOptions(): LanguageOption[] { | ||||
|     return [{code: "", name: $localize`Use system language`}].concat(this.settings.getLanguageOptions()) | ||||
|     return [ | ||||
|       {code: "", name: $localize`Use system language`} | ||||
|     ].concat(this.settings.getLanguageOptions()) | ||||
|   } | ||||
|  | ||||
|   get dateLocaleOptions(): LanguageOption[] { | ||||
|     return [ | ||||
|       {code: "", name: $localize`Use date format of display language`}, | ||||
|       {code: "iso-8601", name: $localize`ISO 8601`} | ||||
|     ].concat(this.settings.getLanguageOptions()) | ||||
|       {code: "", name: $localize`Use date format of display language`} | ||||
|     ].concat(this.settings.getDateLocaleOptions()) | ||||
|   } | ||||
|  | ||||
|   get today() { | ||||
|   | ||||
| @@ -20,7 +20,7 @@ | ||||
|  | ||||
|       <app-input-check i18n-title title="Inbox tag" formControlName="is_inbox_tag" i18n-hint hint="Inbox tags are automatically assigned to all consumed documents."></app-input-check> | ||||
|       <app-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select> | ||||
|       <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match"></app-input-text> | ||||
|       <app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text> | ||||
|       <app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check> | ||||
|     </div> | ||||
|     <div class="modal-footer"> | ||||
|   | ||||
							
								
								
									
										16
									
								
								src-ui/src/app/interceptors/api-version.interceptor.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src-ui/src/app/interceptors/api-version.interceptor.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| import { TestBed } from '@angular/core/testing'; | ||||
|  | ||||
| import { ApiVersionInterceptor } from './api-version.interceptor'; | ||||
|  | ||||
| describe('ApiVersionInterceptor', () => { | ||||
|   beforeEach(() => TestBed.configureTestingModule({ | ||||
|     providers: [ | ||||
|       ApiVersionInterceptor | ||||
|       ] | ||||
|   })); | ||||
|  | ||||
|   it('should be created', () => { | ||||
|     const interceptor: ApiVersionInterceptor = TestBed.inject(ApiVersionInterceptor); | ||||
|     expect(interceptor).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										25
									
								
								src-ui/src/app/interceptors/api-version.interceptor.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src-ui/src/app/interceptors/api-version.interceptor.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { | ||||
|   HttpRequest, | ||||
|   HttpHandler, | ||||
|   HttpEvent, | ||||
|   HttpInterceptor | ||||
| } from '@angular/common/http'; | ||||
| import { Observable } from 'rxjs'; | ||||
| import { environment } from 'src/environments/environment'; | ||||
|  | ||||
| @Injectable() | ||||
| export class ApiVersionInterceptor implements HttpInterceptor { | ||||
|  | ||||
|   constructor() {} | ||||
|  | ||||
|   intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { | ||||
|     request = request.clone({ | ||||
|         setHeaders: { | ||||
|           'Accept': `application/json; version=${environment.apiVersion}` | ||||
|         } | ||||
|       }) | ||||
|   | ||||
|     return next.handle(request); | ||||
|   } | ||||
| } | ||||
| @@ -13,17 +13,20 @@ const FORMAT_TO_ISO_FORMAT = { | ||||
| }) | ||||
| export class CustomDatePipe extends DatePipe implements PipeTransform { | ||||
|  | ||||
|   private defaultLocale: string | ||||
|  | ||||
|   constructor(@Inject(LOCALE_ID) locale: string, private settings: SettingsService) { | ||||
|     super(locale) | ||||
|     this.defaultLocale = locale | ||||
|   } | ||||
|  | ||||
|   transform(value: any, format?: string, timezone?: string, locale?: string): string | null { | ||||
|     let l = locale || this.settings.get(SETTINGS_KEYS.DATE_LOCALE) | ||||
|     let l = locale || this.settings.get(SETTINGS_KEYS.DATE_LOCALE) || this.defaultLocale | ||||
|     let f = format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT) | ||||
|     if (l == "iso-8601") { | ||||
|       return super.transform(value, FORMAT_TO_ISO_FORMAT[f], timezone) | ||||
|     } else { | ||||
|       return super.transform(value, format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), timezone, locale) | ||||
|       return super.transform(value, format || this.settings.get(SETTINGS_KEYS.DATE_FORMAT), timezone, l) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { DOCUMENT } from '@angular/common'; | ||||
| import { Inject, Injectable, Renderer2, RendererFactory2 } from '@angular/core'; | ||||
| import { Inject, Injectable, LOCALE_ID, Renderer2, RendererFactory2 } from '@angular/core'; | ||||
| import { Meta } from '@angular/platform-browser'; | ||||
| import { CookieService } from 'ngx-cookie-service'; | ||||
|  | ||||
| @@ -10,9 +10,14 @@ export interface PaperlessSettings { | ||||
| } | ||||
|  | ||||
| export interface LanguageOption { | ||||
|   code: string, | ||||
|   name: string, | ||||
|   code: string | ||||
|   name: string | ||||
|   englishName?: string | ||||
|  | ||||
|   /** | ||||
|    * A date format string for use by the date selectors. MUST contain 'yyyy', 'mm' and 'dd'. | ||||
|    */ | ||||
|   dateInputFormat?: string | ||||
| } | ||||
|  | ||||
| export const SETTINGS_KEYS = { | ||||
| @@ -56,7 +61,8 @@ export class SettingsService { | ||||
|     private rendererFactory: RendererFactory2, | ||||
|     @Inject(DOCUMENT) private document, | ||||
|     private cookieService: CookieService, | ||||
|     private meta: Meta | ||||
|     private meta: Meta, | ||||
|     @Inject(LOCALE_ID) private localeId: string | ||||
|   ) { | ||||
|     this.renderer = rendererFactory.createRenderer(null, null); | ||||
|  | ||||
| @@ -79,14 +85,20 @@ export class SettingsService { | ||||
|  | ||||
|   getLanguageOptions(): LanguageOption[] { | ||||
|     return [ | ||||
|       {code: "en-us", name: $localize`English (US)`, englishName: "English (US)"}, | ||||
|       {code: "en-gb", name: $localize`English (GB)`, englishName: "English (GB)"}, | ||||
|       {code: "de", name: $localize`German`, englishName: "German"}, | ||||
|       {code: "nl", name: $localize`Dutch`, englishName: "Dutch"}, | ||||
|       {code: "fr", name: $localize`French`, englishName: "French"} | ||||
|       {code: "en-us", name: $localize`English (US)`, englishName: "English (US)", dateInputFormat: "mm/dd/yyyy"}, | ||||
|       {code: "en-gb", name: $localize`English (GB)`, englishName: "English (GB)", dateInputFormat: "dd/mm/yyyy"}, | ||||
|       {code: "de", name: $localize`German`, englishName: "German", dateInputFormat: "dd.mm.yyyy"}, | ||||
|       {code: "nl", name: $localize`Dutch`, englishName: "Dutch", dateInputFormat: "dd-mm-yyyy"}, | ||||
|       {code: "fr", name: $localize`French`, englishName: "French", dateInputFormat: "dd/mm/yyyy"}, | ||||
|       {code: "pt-br", name: $localize`Portuguese (Brazil)`, englishName: "Portuguese (Brazil)", dateInputFormat: "dd/mm/yyyy"} | ||||
|     ] | ||||
|   } | ||||
|  | ||||
|   getDateLocaleOptions(): LanguageOption[] { | ||||
|     let isoOption: LanguageOption = {code: "iso-8601", name: $localize`ISO 8601`, dateInputFormat: "yyyy-mm-dd"} | ||||
|     return [isoOption].concat(this.getLanguageOptions()) | ||||
|   } | ||||
|  | ||||
|   private getLanguageCookieName() { | ||||
|     let prefix = "" | ||||
|     if (this.meta.getTag('name=cookie_prefix')) { | ||||
| @@ -107,6 +119,11 @@ export class SettingsService { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   getLocalizedDateInputFormat(): string { | ||||
|     let dateLocale = this.get(SETTINGS_KEYS.DATE_LOCALE) || this.getLanguage() || this.localeId.toLowerCase() | ||||
|     return this.getDateLocaleOptions().find(o => o.code == dateLocale)?.dateInputFormat || "yyyy-mm-dd" | ||||
|   } | ||||
|  | ||||
|   get(key: string): any { | ||||
|     let setting = SETTINGS.find(s => s.key == key) | ||||
|  | ||||
|   | ||||
							
								
								
									
										59
									
								
								src-ui/src/app/utils/ngb-date-parser-formatter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src-ui/src/app/utils/ngb-date-parser-formatter.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| import { Injectable } from "@angular/core" | ||||
| import { NgbDateParserFormatter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap" | ||||
| import { SettingsService } from "../services/settings.service" | ||||
|  | ||||
| @Injectable() | ||||
| export class LocalizedDateParserFormatter extends NgbDateParserFormatter { | ||||
|  | ||||
|   constructor(private settings: SettingsService) { | ||||
|     super() | ||||
|   } | ||||
|  | ||||
|   private getDateInputFormat() { | ||||
|     return this.settings.getLocalizedDateInputFormat() | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * This constructs a regular expression from a date input format which is then | ||||
|    * used to parse dates. | ||||
|    */ | ||||
|   private getDateParseRegex() { | ||||
|     return new RegExp( | ||||
|       "^" + this.getDateInputFormat() | ||||
|       .replace('dd', '(?<day>[0-9]+)') | ||||
|       .replace('mm', '(?<month>[0-9]+)') | ||||
|       .replace('yyyy', '(?<year>[0-9]+)') | ||||
|       .split('.').join('\\.\\s*') + "$" // allow whitespace(s) after dot (specific for German) | ||||
|       ) | ||||
|   } | ||||
|  | ||||
|   parse(value: string): NgbDateStruct | null { | ||||
|     let match = this.getDateParseRegex().exec(value) | ||||
|     if (match) { | ||||
|       let dateStruct = { | ||||
|         day: +match.groups.day, | ||||
|         month: +match.groups.month, | ||||
|         year: +match.groups.year | ||||
|       } | ||||
|       if (dateStruct.year <= (new Date().getFullYear() - 2000)) { | ||||
|         dateStruct.year += 2000 | ||||
|       } else if (dateStruct.year < 100) { | ||||
|         dateStruct.year += 1900 | ||||
|       } | ||||
|       return dateStruct | ||||
|     } else { | ||||
|       return null | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   format(date: NgbDateStruct | null): string { | ||||
|     if (date) { | ||||
|       return this.getDateInputFormat() | ||||
|       .replace('dd', date.day.toString().padStart(2, '0')) | ||||
|       .replace('mm', date.month.toString().padStart(2, '0')) | ||||
|       .replace('yyyy', date.year.toString().padStart(4, '0')) | ||||
|     } else { | ||||
|       return null | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										27
									
								
								src-ui/src/app/utils/ngb-iso-date-adapter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src-ui/src/app/utils/ngb-iso-date-adapter.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| import { Injectable } from "@angular/core"; | ||||
| import { NgbDateAdapter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap"; | ||||
|  | ||||
| @Injectable() | ||||
| export class ISODateAdapter extends NgbDateAdapter<string> { | ||||
|  | ||||
|   fromModel(value: string | null): NgbDateStruct | null { | ||||
|     if (value) { | ||||
|       let date = new Date(value) | ||||
|       return { | ||||
|         day : date.getDate(), | ||||
|         month : date.getMonth() + 1, | ||||
|         year : date.getFullYear() | ||||
|       } | ||||
|     } else { | ||||
|       return null | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   toModel(date: NgbDateStruct | null): string | null { | ||||
|     if (date) { | ||||
|       return date.year.toString().padStart(4, '0') + "-" + date.month.toString().padStart(2, '0') + "-" + date.day.toString().padStart(2, '0') | ||||
|     } else { | ||||
|       return null | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										23
									
								
								src-ui/src/app/utils/ngb-iso-date-time-adapter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src-ui/src/app/utils/ngb-iso-date-time-adapter.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| import { Injectable } from "@angular/core"; | ||||
| import { NgbDateAdapter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap"; | ||||
|  | ||||
| @Injectable() | ||||
| export class ISODateTimeAdapter extends NgbDateAdapter<string> { | ||||
|  | ||||
|   fromModel(value: string | null): NgbDateStruct | null { | ||||
|     if (value) { | ||||
|       let date = new Date(value) | ||||
|       return { | ||||
|         day : date.getDate(), | ||||
|         month : date.getMonth() + 1, | ||||
|         year : date.getFullYear() | ||||
|       } | ||||
|     } else { | ||||
|       return null | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   toModel(date: NgbDateStruct | null): string | null { | ||||
|     return date ? new Date(date.year, date.month - 1, date.day).toISOString() : null | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								src-ui/src/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src-ui/src/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 6.1 KiB | 
| @@ -1,8 +1,9 @@ | ||||
| export const environment = { | ||||
|   production: true, | ||||
|   apiBaseUrl: "/api/", | ||||
|   apiVersion: "1", | ||||
|   appTitle: "Paperless-ng", | ||||
|   version: "1.2.0", | ||||
|   version: "1.2.1", | ||||
|   webSocketHost: window.location.host, | ||||
|   webSocketProtocol: (window.location.protocol == "https:" ? "wss:" : "ws:") | ||||
| }; | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| export const environment = { | ||||
|   production: false, | ||||
|   apiBaseUrl: "http://localhost:8000/api/", | ||||
|   apiVersion: "1", | ||||
|   appTitle: "Paperless-ng", | ||||
|   version: "DEVELOPMENT", | ||||
|   webSocketHost: "localhost:8000", | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
|   <meta name="theme-color" content="#17541f" /> | ||||
|   <link rel="manifest" href="manifest.webmanifest"> | ||||
|   <link rel="icon" type="image/x-icon" href="favicon.ico"> | ||||
|   <link rel="apple-touch-icon" href="apple-touch-icon.png"> | ||||
| </head> | ||||
| <body class="color-scheme-system"> | ||||
|   <app-root></app-root> | ||||
|   | ||||
| @@ -606,7 +606,7 @@ | ||||
|         <target>Benutze Systemsprache</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">91</context> | ||||
|           <context context-type="linenumber">92</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="7729897675462249787"> | ||||
| @@ -614,15 +614,7 @@ | ||||
|         <target>Benutze Datumsformat der Anzeigesprache</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">96</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="4912706592792948707"> | ||||
|         <source>ISO 8601</source> | ||||
|         <target>ISO 8601</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">97</context> | ||||
|           <context context-type="linenumber">98</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="8488620293789898901"> | ||||
| @@ -630,7 +622,7 @@ | ||||
|         <target>Fehler beim Speichern der Einstellungen auf dem Server: <x equiv-text="JSON.stringify(error.error)" id="PH"/></target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">114</context> | ||||
|           <context context-type="linenumber">115</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="121cc5391cd2a5115bc2b3160379ee5b36cd7716"> | ||||
| @@ -1832,6 +1824,14 @@ | ||||
|           <context context-type="linenumber">21</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="d6529debfc1613db22d6fa096ebfeb8a85fa739d"> | ||||
|         <source>Invalid date.</source> | ||||
|         <target>Ungültiges Datum.</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context> | ||||
|           <context context-type="linenumber">13</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="2807800733729323332"> | ||||
|         <source>Yes</source> | ||||
|         <target>Ja</target> | ||||
| @@ -1861,7 +1861,7 @@ | ||||
|         <target>Englisch (US)</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">82</context> | ||||
|           <context context-type="linenumber">88</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="6987083569809053351"> | ||||
| @@ -1869,7 +1869,7 @@ | ||||
|         <target>Englisch (UK)</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">83</context> | ||||
|           <context context-type="linenumber">89</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="1858110241312746425"> | ||||
| @@ -1877,7 +1877,7 @@ | ||||
|         <target>Deutsch</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">84</context> | ||||
|           <context context-type="linenumber">90</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="3071065188816255493"> | ||||
| @@ -1885,7 +1885,7 @@ | ||||
|         <target>Niederländisch</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">85</context> | ||||
|           <context context-type="linenumber">91</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="7633754075223722162"> | ||||
| @@ -1893,7 +1893,23 @@ | ||||
|         <target>Französisch</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">86</context> | ||||
|           <context context-type="linenumber">92</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="9184513005098760425"> | ||||
|         <source>Portuguese (Brazil)</source> | ||||
|         <target>Portugiesisch (Brasilien)</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">93</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="4912706592792948707"> | ||||
|         <source>ISO 8601</source> | ||||
|         <target>ISO 8601</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">98</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="2119857572761283468"> | ||||
|   | ||||
| @@ -606,7 +606,7 @@ | ||||
|         <target>Use system language</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">91</context> | ||||
|           <context context-type="linenumber">92</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="7729897675462249787"> | ||||
| @@ -614,15 +614,7 @@ | ||||
|         <target>Use date format of display language</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">96</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="4912706592792948707"> | ||||
|         <source>ISO 8601</source> | ||||
|         <target>ISO 8601</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">97</context> | ||||
|           <context context-type="linenumber">98</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="8488620293789898901"> | ||||
| @@ -630,7 +622,7 @@ | ||||
|         <target>Error while storing settings on server: <x equiv-text="JSON.stringify(error.error)" id="PH"/></target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">114</context> | ||||
|           <context context-type="linenumber">115</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="121cc5391cd2a5115bc2b3160379ee5b36cd7716"> | ||||
| @@ -1832,6 +1824,14 @@ | ||||
|           <context context-type="linenumber">21</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="d6529debfc1613db22d6fa096ebfeb8a85fa739d"> | ||||
|         <source>Invalid date.</source> | ||||
|         <target>Invalid date.</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context> | ||||
|           <context context-type="linenumber">13</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="2807800733729323332"> | ||||
|         <source>Yes</source> | ||||
|         <target>Yes</target> | ||||
| @@ -1861,7 +1861,7 @@ | ||||
|         <target>English (US)</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">82</context> | ||||
|           <context context-type="linenumber">88</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="6987083569809053351"> | ||||
| @@ -1869,7 +1869,7 @@ | ||||
|         <target>English (GB)</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">83</context> | ||||
|           <context context-type="linenumber">89</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="1858110241312746425"> | ||||
| @@ -1877,7 +1877,7 @@ | ||||
|         <target>German</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">84</context> | ||||
|           <context context-type="linenumber">90</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="3071065188816255493"> | ||||
| @@ -1885,7 +1885,7 @@ | ||||
|         <target>Dutch</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">85</context> | ||||
|           <context context-type="linenumber">91</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="7633754075223722162"> | ||||
| @@ -1893,7 +1893,23 @@ | ||||
|         <target>French</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">86</context> | ||||
|           <context context-type="linenumber">92</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="9184513005098760425"> | ||||
|         <source>Portuguese (Brazil)</source> | ||||
|         <target>Portuguese (Brazil)</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">93</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="4912706592792948707"> | ||||
|         <source>ISO 8601</source> | ||||
|         <target>ISO 8601</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">98</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="2119857572761283468"> | ||||
|   | ||||
| @@ -606,7 +606,7 @@ | ||||
|         <target>Utiliser la langue du système</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">91</context> | ||||
|           <context context-type="linenumber">92</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="7729897675462249787"> | ||||
| @@ -614,15 +614,7 @@ | ||||
|         <target>Utiliser le format de date de la langue d'affichage</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">96</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="4912706592792948707"> | ||||
|         <source>ISO 8601</source> | ||||
|         <target>ISO 8601</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">97</context> | ||||
|           <context context-type="linenumber">98</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="8488620293789898901"> | ||||
| @@ -630,7 +622,7 @@ | ||||
|         <target>Une erreur s'est produite lors de l'enregistrement des paramètres sur le serveur : <x equiv-text="JSON.stringify(error.error)" id="PH"/></target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.ts</context> | ||||
|           <context context-type="linenumber">114</context> | ||||
|           <context context-type="linenumber">115</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="121cc5391cd2a5115bc2b3160379ee5b36cd7716"> | ||||
| @@ -819,7 +811,7 @@ | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="8680abbea249ebe9c2fe35556559c8e1a9eb5841"> | ||||
|         <source>Document processing</source> | ||||
|         <target>Traitement de document</target> | ||||
|         <target>Traitement de documents</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/manage/settings/settings.component.html</context> | ||||
|           <context context-type="linenumber">118</context> | ||||
| @@ -1832,6 +1824,14 @@ | ||||
|           <context context-type="linenumber">21</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="d6529debfc1613db22d6fa096ebfeb8a85fa739d"> | ||||
|         <source>Invalid date.</source> | ||||
|         <target>Date incorrecte.</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/components/common/input/date/date.component.html</context> | ||||
|           <context context-type="linenumber">13</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="2807800733729323332"> | ||||
|         <source>Yes</source> | ||||
|         <target>Oui</target> | ||||
| @@ -1861,7 +1861,7 @@ | ||||
|         <target>Anglais (US)</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">82</context> | ||||
|           <context context-type="linenumber">88</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="6987083569809053351"> | ||||
| @@ -1869,7 +1869,7 @@ | ||||
|         <target>Anglais (GB)</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">83</context> | ||||
|           <context context-type="linenumber">89</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="1858110241312746425"> | ||||
| @@ -1877,7 +1877,7 @@ | ||||
|         <target>Allemand</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">84</context> | ||||
|           <context context-type="linenumber">90</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="3071065188816255493"> | ||||
| @@ -1885,7 +1885,7 @@ | ||||
|         <target>Néerlandais</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">85</context> | ||||
|           <context context-type="linenumber">91</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="7633754075223722162"> | ||||
| @@ -1893,7 +1893,23 @@ | ||||
|         <target>Français</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">86</context> | ||||
|           <context context-type="linenumber">92</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="9184513005098760425"> | ||||
|         <source>Portuguese (Brazil)</source> | ||||
|         <target>Portugais (Brésil)</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">93</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="4912706592792948707"> | ||||
|         <source>ISO 8601</source> | ||||
|         <target>ISO 8601</target> | ||||
|         <context-group purpose="location"> | ||||
|           <context context-type="sourcefile">src/app/services/settings.service.ts</context> | ||||
|           <context context-type="linenumber">98</context> | ||||
|         </context-group> | ||||
|       </trans-unit> | ||||
|       <trans-unit datatype="html" id="2119857572761283468"> | ||||
|   | ||||
							
								
								
									
										2353
									
								
								src-ui/src/locale/messages.pt_BR.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2353
									
								
								src-ui/src/locale/messages.pt_BR.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -246,6 +246,16 @@ $border-color-dark-mode: #47494f; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .btn-light:not(:disabled):not(.disabled) { | ||||
|     background-color: $bg-dark-mode; | ||||
|     color: $text-color-dark-mode-accent; | ||||
|  | ||||
|     &:hover { | ||||
|       background-color: $text-color-dark-mode; | ||||
|       color: $bg-dark-mode; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .btn-link:not(:disabled):not(.disabled) { | ||||
|     color: $primary-dark-mode; | ||||
|   } | ||||
| @@ -366,6 +376,12 @@ $border-color-dark-mode: #47494f; | ||||
|   .progress-bar.bg-primary { | ||||
|     background-color: darken($primary-dark-mode, 5%) !important; | ||||
|   } | ||||
|  | ||||
|   .ngb-dp-header, | ||||
|   .ngb-dp-weekdays, | ||||
|   .ngb-dp-month { | ||||
|     background-color: $bg-light-dark-mode; | ||||
|   } | ||||
| } | ||||
|  | ||||
| body.color-scheme-dark { | ||||
|   | ||||
| @@ -1,11 +1,13 @@ | ||||
| import re | ||||
|  | ||||
| import magic | ||||
| from django.utils.text import slugify | ||||
| from rest_framework import serializers | ||||
| from rest_framework.fields import SerializerMethodField | ||||
|  | ||||
| from . import bulk_edit | ||||
| from .models import Correspondent, Tag, Document, Log, DocumentType, \ | ||||
|     SavedView, SavedViewFilterRule | ||||
| from .models import Correspondent, Tag, Document, DocumentType, \ | ||||
|     SavedView, SavedViewFilterRule, MatchingModel | ||||
| from .parsers import is_mime_type_supported | ||||
|  | ||||
| from django.utils.translation import gettext as _ | ||||
| @@ -33,16 +35,30 @@ class DynamicFieldsModelSerializer(serializers.ModelSerializer): | ||||
|                 self.fields.pop(field_name) | ||||
|  | ||||
|  | ||||
| class CorrespondentSerializer(serializers.ModelSerializer): | ||||
| class MatchingModelSerializer(serializers.ModelSerializer): | ||||
|  | ||||
|     document_count = serializers.IntegerField(read_only=True) | ||||
|  | ||||
|     last_correspondence = serializers.DateTimeField(read_only=True) | ||||
|  | ||||
|     def get_slug(self, obj): | ||||
|         return slugify(obj.name) | ||||
|     slug = SerializerMethodField() | ||||
|  | ||||
|     def validate_match(self, match): | ||||
|         if 'matching_algorithm' in self.initial_data and self.initial_data['matching_algorithm'] == MatchingModel.MATCH_REGEX:  # NOQA: E501 | ||||
|             try: | ||||
|                 re.compile(match) | ||||
|             except Exception as e: | ||||
|                 raise serializers.ValidationError( | ||||
|                     _("Invalid regular expresssion: %(error)s") % | ||||
|                     {'error': str(e)} | ||||
|                 ) | ||||
|         return match | ||||
|  | ||||
|  | ||||
| class CorrespondentSerializer(MatchingModelSerializer): | ||||
|  | ||||
|     last_correspondence = serializers.DateTimeField(read_only=True) | ||||
|  | ||||
|     class Meta: | ||||
|         model = Correspondent | ||||
|         fields = ( | ||||
| @@ -57,13 +73,7 @@ class CorrespondentSerializer(serializers.ModelSerializer): | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class DocumentTypeSerializer(serializers.ModelSerializer): | ||||
|  | ||||
|     document_count = serializers.IntegerField(read_only=True) | ||||
|  | ||||
|     def get_slug(self, obj): | ||||
|         return slugify(obj.name) | ||||
|     slug = SerializerMethodField() | ||||
| class DocumentTypeSerializer(MatchingModelSerializer): | ||||
|  | ||||
|     class Meta: | ||||
|         model = DocumentType | ||||
| @@ -78,13 +88,7 @@ class DocumentTypeSerializer(serializers.ModelSerializer): | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class TagSerializer(serializers.ModelSerializer): | ||||
|  | ||||
|     document_count = serializers.IntegerField(read_only=True) | ||||
|  | ||||
|     def get_slug(self, obj): | ||||
|         return slugify(obj.name) | ||||
|     slug = SerializerMethodField() | ||||
| class TagSerializer(MatchingModelSerializer): | ||||
|  | ||||
|     class Meta: | ||||
|         model = Tag | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
|   <link rel="icon" type="image/x-icon" href="favicon.ico"> | ||||
|   <link rel="manifest" href="{% static webmanifest %}"> | ||||
| 	<link rel="stylesheet" href="{% static styles_css %}"> | ||||
| 	<link rel="apple-touch-icon" href="apple-touch-icon.png"> | ||||
| </head> | ||||
| <body> | ||||
|   <app-root>{% translate "Paperless-ng is loading..." %}</app-root> | ||||
|   | ||||
| @@ -14,7 +14,7 @@ from rest_framework.test import APITestCase | ||||
| from whoosh.writing import AsyncWriter | ||||
|  | ||||
| from documents import index, bulk_edit | ||||
| from documents.models import Document, Correspondent, DocumentType, Tag, SavedView | ||||
| from documents.models import Document, Correspondent, DocumentType, Tag, SavedView, MatchingModel | ||||
| from documents.tests.utils import DirectoriesMixin | ||||
|  | ||||
|  | ||||
| @@ -772,6 +772,41 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         self.assertListEqual(response.data, ["test", "test2"]) | ||||
|  | ||||
|     def test_invalid_regex_other_algorithm(self): | ||||
|         for endpoint in ['correspondents', 'tags', 'document_types']: | ||||
|             response = self.client.post(f"/api/{endpoint}/", { | ||||
|                 "name": "test", | ||||
|                 "matching_algorithm": MatchingModel.MATCH_ANY, | ||||
|                 "match": "[" | ||||
|             }, format='json') | ||||
|             self.assertEqual(response.status_code, 201, endpoint) | ||||
|  | ||||
|     def test_invalid_regex(self): | ||||
|         for endpoint in ['correspondents', 'tags', 'document_types']: | ||||
|             response = self.client.post(f"/api/{endpoint}/", { | ||||
|                 "name": "test", | ||||
|                 "matching_algorithm": MatchingModel.MATCH_REGEX, | ||||
|                 "match": "[" | ||||
|             }, format='json') | ||||
|             self.assertEqual(response.status_code, 400, endpoint) | ||||
|  | ||||
|     def test_valid_regex(self): | ||||
|         for endpoint in ['correspondents', 'tags', 'document_types']: | ||||
|             response = self.client.post(f"/api/{endpoint}/", { | ||||
|                 "name": "test", | ||||
|                 "matching_algorithm": MatchingModel.MATCH_REGEX, | ||||
|                 "match": "[0-9]" | ||||
|             }, format='json') | ||||
|             self.assertEqual(response.status_code, 201, endpoint) | ||||
|  | ||||
|     def test_regex_no_algorithm(self): | ||||
|         for endpoint in ['correspondents', 'tags', 'document_types']: | ||||
|             response = self.client.post(f"/api/{endpoint}/", { | ||||
|                 "name": "test", | ||||
|                 "match": "[0-9]" | ||||
|             }, format='json') | ||||
|             self.assertEqual(response.status_code, 201, endpoint) | ||||
|  | ||||
|  | ||||
| class TestBulkEdit(DirectoriesMixin, APITestCase): | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: PACKAGE VERSION\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2021-02-16 14:52+0100\n" | ||||
| "POT-Creation-Date: 2021-02-24 16:49+0100\n" | ||||
| "PO-Revision-Date: 2021-02-16 18:37+0000\n" | ||||
| "Last-Translator: Jonas Winkler, 2021\n" | ||||
| "Language-Team: German (https://www.transifex.com/paperless/teams/115905/de/)\n" | ||||
| @@ -354,7 +354,12 @@ msgstr "Filterregel" | ||||
| msgid "filter rules" | ||||
| msgstr "Filterregeln" | ||||
|  | ||||
| #: documents/serialisers.py:370 | ||||
| #: documents/serialisers.py:52 | ||||
| #, python-format | ||||
| msgid "Invalid regular expresssion: %(error)s" | ||||
| msgstr "Ungültiger regulärer Ausdruck: %(error)s" | ||||
|  | ||||
| #: documents/serialisers.py:378 | ||||
| #, python-format | ||||
| msgid "File type %(type)s not supported" | ||||
| msgstr "Dateityp %(type)s nicht unterstützt" | ||||
| @@ -421,7 +426,11 @@ msgstr "Niederländisch" | ||||
| msgid "French" | ||||
| msgstr "Französisch" | ||||
|  | ||||
| #: paperless/urls.py:114 | ||||
| #: paperless/settings.py:296 | ||||
| msgid "Portuguese (Brazil)" | ||||
| msgstr "Portugiesisch (Brasilien)" | ||||
|  | ||||
| #: paperless/urls.py:118 | ||||
| msgid "Paperless-ng administration" | ||||
| msgstr "Paperless-ng Administration" | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: PACKAGE VERSION\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2021-02-16 14:52+0100\n" | ||||
| "POT-Creation-Date: 2021-02-24 16:49+0100\n" | ||||
| "PO-Revision-Date: 2021-02-16 18:37+0000\n" | ||||
| "Last-Translator: Jonas Winkler, 2021\n" | ||||
| "Language-Team: English (United Kingdom) (https://www.transifex.com/paperless/teams/115905/en_GB/)\n" | ||||
| @@ -355,7 +355,12 @@ msgstr "filter rule" | ||||
| msgid "filter rules" | ||||
| msgstr "filter rules" | ||||
|  | ||||
| #: documents/serialisers.py:370 | ||||
| #: documents/serialisers.py:52 | ||||
| #, python-format | ||||
| msgid "Invalid regular expresssion: %(error)s" | ||||
| msgstr "Invalid regular expresssion: %(error)s" | ||||
|  | ||||
| #: documents/serialisers.py:378 | ||||
| #, python-format | ||||
| msgid "File type %(type)s not supported" | ||||
| msgstr "File type %(type)s not supported" | ||||
| @@ -420,7 +425,11 @@ msgstr "Dutch" | ||||
| msgid "French" | ||||
| msgstr "French" | ||||
|  | ||||
| #: paperless/urls.py:114 | ||||
| #: paperless/settings.py:296 | ||||
| msgid "Portuguese (Brazil)" | ||||
| msgstr "Portuguese (Brazil)" | ||||
|  | ||||
| #: paperless/urls.py:118 | ||||
| msgid "Paperless-ng administration" | ||||
| msgstr "Paperless-ng administration" | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: PACKAGE VERSION\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2021-02-16 14:52+0100\n" | ||||
| "POT-Creation-Date: 2021-02-24 16:49+0100\n" | ||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | ||||
| @@ -346,7 +346,12 @@ msgstr "" | ||||
| msgid "filter rules" | ||||
| msgstr "" | ||||
|  | ||||
| #: documents/serialisers.py:370 | ||||
| #: documents/serialisers.py:52 | ||||
| #, python-format | ||||
| msgid "Invalid regular expresssion: %(error)s" | ||||
| msgstr "" | ||||
|  | ||||
| #: documents/serialisers.py:378 | ||||
| #, python-format | ||||
| msgid "File type %(type)s not supported" | ||||
| msgstr "" | ||||
| @@ -411,7 +416,11 @@ msgstr "" | ||||
| msgid "French" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/urls.py:114 | ||||
| #: paperless/settings.py:296 | ||||
| msgid "Portuguese (Brazil)" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/urls.py:118 | ||||
| msgid "Paperless-ng administration" | ||||
| msgstr "" | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: PACKAGE VERSION\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2021-02-16 14:52+0100\n" | ||||
| "POT-Creation-Date: 2021-02-24 16:49+0100\n" | ||||
| "PO-Revision-Date: 2021-02-16 18:37+0000\n" | ||||
| "Last-Translator: Philmo67, 2021\n" | ||||
| "Language-Team: French (https://www.transifex.com/paperless/teams/115905/fr/)\n" | ||||
| @@ -356,7 +356,12 @@ msgstr "règle de filtrage" | ||||
| msgid "filter rules" | ||||
| msgstr "règles de filtrage" | ||||
|  | ||||
| #: documents/serialisers.py:370 | ||||
| #: documents/serialisers.py:52 | ||||
| #, python-format | ||||
| msgid "Invalid regular expresssion: %(error)s" | ||||
| msgstr "Expression régulière incorrecte : %(error)s" | ||||
|  | ||||
| #: documents/serialisers.py:378 | ||||
| #, python-format | ||||
| msgid "File type %(type)s not supported" | ||||
| msgstr "Type de fichier %(type)s non pris en charge" | ||||
| @@ -423,7 +428,11 @@ msgstr "Néerlandais" | ||||
| msgid "French" | ||||
| msgstr "Français" | ||||
|  | ||||
| #: paperless/urls.py:114 | ||||
| #: paperless/settings.py:296 | ||||
| msgid "Portuguese (Brazil)" | ||||
| msgstr "Portugais (Brésil)" | ||||
|  | ||||
| #: paperless/urls.py:118 | ||||
| msgid "Paperless-ng administration" | ||||
| msgstr "Administration de Paperless-ng" | ||||
|  | ||||
|   | ||||
							
								
								
									
										672
									
								
								src/locale/pt_BR/LC_MESSAGES/django.po
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										672
									
								
								src/locale/pt_BR/LC_MESSAGES/django.po
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,672 @@ | ||||
| # SOME DESCRIPTIVE TITLE. | ||||
| # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER | ||||
| # This file is distributed under the same license as the PACKAGE package. | ||||
| # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. | ||||
| #  | ||||
| # Translators: | ||||
| # Jonas Winkler, 2021 | ||||
| # Rodrigo A <rodrigo.avelino@meliuz.com.br>, 2021 | ||||
| #  | ||||
| #, fuzzy | ||||
| msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: PACKAGE VERSION\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2021-02-24 16:49+0100\n" | ||||
| "PO-Revision-Date: 2021-02-16 18:37+0000\n" | ||||
| "Last-Translator: Rodrigo A <rodrigo.avelino@meliuz.com.br>, 2021\n" | ||||
| "Language-Team: Portuguese (Brazil) (https://www.transifex.com/paperless/teams/115905/pt_BR/)\n" | ||||
| "MIME-Version: 1.0\n" | ||||
| "Content-Type: text/plain; charset=UTF-8\n" | ||||
| "Content-Transfer-Encoding: 8bit\n" | ||||
| "Language: pt_BR\n" | ||||
| "Plural-Forms: nplurals=2; plural=(n > 1);\n" | ||||
|  | ||||
| #: documents/apps.py:10 | ||||
| msgid "Documents" | ||||
| msgstr "Documentos" | ||||
|  | ||||
| #: documents/models.py:32 | ||||
| msgid "Any word" | ||||
| msgstr "Qualquer palavra" | ||||
|  | ||||
| #: documents/models.py:33 | ||||
| msgid "All words" | ||||
| msgstr "Todas as palavras" | ||||
|  | ||||
| #: documents/models.py:34 | ||||
| msgid "Exact match" | ||||
| msgstr "Detecção exata" | ||||
|  | ||||
| #: documents/models.py:35 | ||||
| msgid "Regular expression" | ||||
| msgstr "Expressão regular" | ||||
|  | ||||
| #: documents/models.py:36 | ||||
| msgid "Fuzzy word" | ||||
| msgstr "Palavra difusa (fuzzy)" | ||||
|  | ||||
| #: documents/models.py:37 | ||||
| msgid "Automatic" | ||||
| msgstr "Automático" | ||||
|  | ||||
| #: documents/models.py:41 documents/models.py:364 paperless_mail/models.py:25 | ||||
| #: paperless_mail/models.py:109 | ||||
| msgid "name" | ||||
| msgstr "nome" | ||||
|  | ||||
| #: documents/models.py:45 | ||||
| msgid "match" | ||||
| msgstr "detecção" | ||||
|  | ||||
| #: documents/models.py:49 | ||||
| msgid "matching algorithm" | ||||
| msgstr "algoritmo de detecção" | ||||
|  | ||||
| #: documents/models.py:55 | ||||
| msgid "is insensitive" | ||||
| msgstr "diferencia maiúsculas de minúsculas" | ||||
|  | ||||
| #: documents/models.py:74 documents/models.py:134 | ||||
| msgid "correspondent" | ||||
| msgstr "correspondente" | ||||
|  | ||||
| #: documents/models.py:75 | ||||
| msgid "correspondents" | ||||
| msgstr "correspondentes" | ||||
|  | ||||
| #: documents/models.py:97 | ||||
| msgid "color" | ||||
| msgstr "cor" | ||||
|  | ||||
| #: documents/models.py:101 | ||||
| msgid "is inbox tag" | ||||
| msgstr "é etiqueta caixa de entrada" | ||||
|  | ||||
| #: documents/models.py:103 | ||||
| msgid "" | ||||
| "Marks this tag as an inbox tag: All newly consumed documents will be tagged " | ||||
| "with inbox tags." | ||||
| msgstr "" | ||||
| "Marca essa etiqueta como caixa de entrada: Todos os novos documentos " | ||||
| "consumidos terão as etiquetas de caixa de entrada." | ||||
|  | ||||
| #: documents/models.py:108 | ||||
| msgid "tag" | ||||
| msgstr "etiqueta" | ||||
|  | ||||
| #: documents/models.py:109 documents/models.py:165 | ||||
| msgid "tags" | ||||
| msgstr "etiquetas" | ||||
|  | ||||
| #: documents/models.py:115 documents/models.py:147 | ||||
| msgid "document type" | ||||
| msgstr "tipo de documento" | ||||
|  | ||||
| #: documents/models.py:116 | ||||
| msgid "document types" | ||||
| msgstr "tipos de documento" | ||||
|  | ||||
| #: documents/models.py:124 | ||||
| msgid "Unencrypted" | ||||
| msgstr "Não encriptado" | ||||
|  | ||||
| #: documents/models.py:125 | ||||
| msgid "Encrypted with GNU Privacy Guard" | ||||
| msgstr "Encriptado com GNU Privacy Guard" | ||||
|  | ||||
| #: documents/models.py:138 | ||||
| msgid "title" | ||||
| msgstr "título" | ||||
|  | ||||
| #: documents/models.py:151 | ||||
| msgid "content" | ||||
| msgstr "conteúdo" | ||||
|  | ||||
| #: documents/models.py:153 | ||||
| msgid "" | ||||
| "The raw, text-only data of the document. This field is primarily used for " | ||||
| "searching." | ||||
| msgstr "" | ||||
| "O conteúdo de texto bruto do documento. Esse campo é usado principalmente " | ||||
| "para busca." | ||||
|  | ||||
| #: documents/models.py:158 | ||||
| msgid "mime type" | ||||
| msgstr "tipo mime" | ||||
|  | ||||
| #: documents/models.py:169 | ||||
| msgid "checksum" | ||||
| msgstr "some de verificação" | ||||
|  | ||||
| #: documents/models.py:173 | ||||
| msgid "The checksum of the original document." | ||||
| msgstr "A soma de verificação original do documento." | ||||
|  | ||||
| #: documents/models.py:177 | ||||
| msgid "archive checksum" | ||||
| msgstr "Soma de verificação de arquivamento." | ||||
|  | ||||
| #: documents/models.py:182 | ||||
| msgid "The checksum of the archived document." | ||||
| msgstr "A soma de verificação do documento arquivado." | ||||
|  | ||||
| #: documents/models.py:186 documents/models.py:342 | ||||
| msgid "created" | ||||
| msgstr "criado" | ||||
|  | ||||
| #: documents/models.py:190 | ||||
| msgid "modified" | ||||
| msgstr "modificado" | ||||
|  | ||||
| #: documents/models.py:194 | ||||
| msgid "storage type" | ||||
| msgstr "tipo de armazenamento" | ||||
|  | ||||
| #: documents/models.py:202 | ||||
| msgid "added" | ||||
| msgstr "adicionado" | ||||
|  | ||||
| #: documents/models.py:206 | ||||
| msgid "filename" | ||||
| msgstr "nome do arquivo" | ||||
|  | ||||
| #: documents/models.py:212 | ||||
| msgid "Current filename in storage" | ||||
| msgstr "Nome do arquivo atual armazenado" | ||||
|  | ||||
| #: documents/models.py:216 | ||||
| msgid "archive filename" | ||||
| msgstr "nome do arquivo para arquivamento" | ||||
|  | ||||
| #: documents/models.py:222 | ||||
| msgid "Current archive filename in storage" | ||||
| msgstr "Nome do arquivo para arquivamento armazenado" | ||||
|  | ||||
| #: documents/models.py:226 | ||||
| msgid "archive serial number" | ||||
| msgstr "número de sério de arquivamento" | ||||
|  | ||||
| #: documents/models.py:231 | ||||
| msgid "The position of this document in your physical document archive." | ||||
| msgstr "A posição deste documento no seu arquivamento físico." | ||||
|  | ||||
| #: documents/models.py:237 | ||||
| msgid "document" | ||||
| msgstr "documento" | ||||
|  | ||||
| #: documents/models.py:238 | ||||
| msgid "documents" | ||||
| msgstr "documentos" | ||||
|  | ||||
| #: documents/models.py:325 | ||||
| msgid "debug" | ||||
| msgstr "debug" | ||||
|  | ||||
| #: documents/models.py:326 | ||||
| msgid "information" | ||||
| msgstr "informação" | ||||
|  | ||||
| #: documents/models.py:327 | ||||
| msgid "warning" | ||||
| msgstr "aviso" | ||||
|  | ||||
| #: documents/models.py:328 | ||||
| msgid "error" | ||||
| msgstr "erro" | ||||
|  | ||||
| #: documents/models.py:329 | ||||
| msgid "critical" | ||||
| msgstr "crítico" | ||||
|  | ||||
| #: documents/models.py:333 | ||||
| msgid "group" | ||||
| msgstr "grupo" | ||||
|  | ||||
| #: documents/models.py:336 | ||||
| msgid "message" | ||||
| msgstr "mensagem" | ||||
|  | ||||
| #: documents/models.py:339 | ||||
| msgid "level" | ||||
| msgstr "nível" | ||||
|  | ||||
| #: documents/models.py:346 | ||||
| msgid "log" | ||||
| msgstr "log" | ||||
|  | ||||
| #: documents/models.py:347 | ||||
| msgid "logs" | ||||
| msgstr "logs" | ||||
|  | ||||
| #: documents/models.py:358 documents/models.py:408 | ||||
| msgid "saved view" | ||||
| msgstr "visualização" | ||||
|  | ||||
| #: documents/models.py:359 | ||||
| msgid "saved views" | ||||
| msgstr "visualizações" | ||||
|  | ||||
| #: documents/models.py:362 | ||||
| msgid "user" | ||||
| msgstr "usuário" | ||||
|  | ||||
| #: documents/models.py:368 | ||||
| msgid "show on dashboard" | ||||
| msgstr "exibir no painel de controle" | ||||
|  | ||||
| #: documents/models.py:371 | ||||
| msgid "show in sidebar" | ||||
| msgstr "exibir no painel lateral" | ||||
|  | ||||
| #: documents/models.py:375 | ||||
| msgid "sort field" | ||||
| msgstr "ordenar campo" | ||||
|  | ||||
| #: documents/models.py:378 | ||||
| msgid "sort reverse" | ||||
| msgstr "odernar reverso" | ||||
|  | ||||
| #: documents/models.py:384 | ||||
| msgid "title contains" | ||||
| msgstr "título contém" | ||||
|  | ||||
| #: documents/models.py:385 | ||||
| msgid "content contains" | ||||
| msgstr "conteúdo contém" | ||||
|  | ||||
| #: documents/models.py:386 | ||||
| msgid "ASN is" | ||||
| msgstr "NSA é" | ||||
|  | ||||
| #: documents/models.py:387 | ||||
| msgid "correspondent is" | ||||
| msgstr "correspondente é" | ||||
|  | ||||
| #: documents/models.py:388 | ||||
| msgid "document type is" | ||||
| msgstr "tipo de documento é" | ||||
|  | ||||
| #: documents/models.py:389 | ||||
| msgid "is in inbox" | ||||
| msgstr "é caixa de entrada" | ||||
|  | ||||
| #: documents/models.py:390 | ||||
| msgid "has tag" | ||||
| msgstr "contém etiqueta" | ||||
|  | ||||
| #: documents/models.py:391 | ||||
| msgid "has any tag" | ||||
| msgstr "contém qualquer etiqueta" | ||||
|  | ||||
| #: documents/models.py:392 | ||||
| msgid "created before" | ||||
| msgstr "criado antes de" | ||||
|  | ||||
| #: documents/models.py:393 | ||||
| msgid "created after" | ||||
| msgstr "criado depois de" | ||||
|  | ||||
| #: documents/models.py:394 | ||||
| msgid "created year is" | ||||
| msgstr "ano de criação é" | ||||
|  | ||||
| #: documents/models.py:395 | ||||
| msgid "created month is" | ||||
| msgstr "mês de criação é" | ||||
|  | ||||
| #: documents/models.py:396 | ||||
| msgid "created day is" | ||||
| msgstr "dia de criação é" | ||||
|  | ||||
| #: documents/models.py:397 | ||||
| msgid "added before" | ||||
| msgstr "adicionado antes de" | ||||
|  | ||||
| #: documents/models.py:398 | ||||
| msgid "added after" | ||||
| msgstr "adicionado depois de" | ||||
|  | ||||
| #: documents/models.py:399 | ||||
| msgid "modified before" | ||||
| msgstr "modificado antes de" | ||||
|  | ||||
| #: documents/models.py:400 | ||||
| msgid "modified after" | ||||
| msgstr "modificado depois de" | ||||
|  | ||||
| #: documents/models.py:401 | ||||
| msgid "does not have tag" | ||||
| msgstr "não tem etiqueta" | ||||
|  | ||||
| #: documents/models.py:412 | ||||
| msgid "rule type" | ||||
| msgstr "tipo de regra" | ||||
|  | ||||
| #: documents/models.py:416 | ||||
| msgid "value" | ||||
| msgstr "valor" | ||||
|  | ||||
| #: documents/models.py:422 | ||||
| msgid "filter rule" | ||||
| msgstr "regra de filtragem" | ||||
|  | ||||
| #: documents/models.py:423 | ||||
| msgid "filter rules" | ||||
| msgstr "regras de filtragem" | ||||
|  | ||||
| #: documents/serialisers.py:52 | ||||
| #, python-format | ||||
| msgid "Invalid regular expresssion: %(error)s" | ||||
| msgstr "Expressão regular inválida: %(error)s" | ||||
|  | ||||
| #: documents/serialisers.py:378 | ||||
| #, python-format | ||||
| msgid "File type %(type)s not supported" | ||||
| msgstr "Tipo de arquivo %(type)s não suportado" | ||||
|  | ||||
| #: documents/templates/index.html:20 | ||||
| msgid "Paperless-ng is loading..." | ||||
| msgstr "Paperless-ng está carregando..." | ||||
|  | ||||
| #: documents/templates/registration/logged_out.html:13 | ||||
| msgid "Paperless-ng signed out" | ||||
| msgstr "Paperless-ng saiu" | ||||
|  | ||||
| #: documents/templates/registration/logged_out.html:41 | ||||
| msgid "You have been successfully logged out. Bye!" | ||||
| msgstr "Sua sessão foi encerrada com sucesso. Até mais!" | ||||
|  | ||||
| #: documents/templates/registration/logged_out.html:42 | ||||
| msgid "Sign in again" | ||||
| msgstr "Entre novamente" | ||||
|  | ||||
| #: documents/templates/registration/login.html:13 | ||||
| msgid "Paperless-ng sign in" | ||||
| msgstr "Entrar no Paperless-ng" | ||||
|  | ||||
| #: documents/templates/registration/login.html:42 | ||||
| msgid "Please sign in." | ||||
| msgstr "Por favor, entre na sua conta" | ||||
|  | ||||
| #: documents/templates/registration/login.html:45 | ||||
| msgid "Your username and password didn't match. Please try again." | ||||
| msgstr "Seu usuário e senha estão incorretos. Por favor, tente novamente." | ||||
|  | ||||
| #: documents/templates/registration/login.html:48 | ||||
| msgid "Username" | ||||
| msgstr "Usuário" | ||||
|  | ||||
| #: documents/templates/registration/login.html:49 | ||||
| msgid "Password" | ||||
| msgstr "Senha" | ||||
|  | ||||
| #: documents/templates/registration/login.html:54 | ||||
| msgid "Sign in" | ||||
| msgstr "Entrar" | ||||
|  | ||||
| #: paperless/settings.py:291 | ||||
| msgid "English (US)" | ||||
| msgstr "Inglês (EUA)" | ||||
|  | ||||
| #: paperless/settings.py:292 | ||||
| msgid "English (GB)" | ||||
| msgstr "Inglês (GB)" | ||||
|  | ||||
| #: paperless/settings.py:293 | ||||
| msgid "German" | ||||
| msgstr "Alemão" | ||||
|  | ||||
| #: paperless/settings.py:294 | ||||
| msgid "Dutch" | ||||
| msgstr "Holandês" | ||||
|  | ||||
| #: paperless/settings.py:295 | ||||
| msgid "French" | ||||
| msgstr "Francês" | ||||
|  | ||||
| #: paperless/settings.py:296 | ||||
| msgid "Portuguese (Brazil)" | ||||
| msgstr "Português (Brasil)" | ||||
|  | ||||
| #: paperless/urls.py:118 | ||||
| msgid "Paperless-ng administration" | ||||
| msgstr "Administração do Paperless-ng" | ||||
|  | ||||
| #: paperless_mail/admin.py:25 | ||||
| msgid "Filter" | ||||
| msgstr "Filtro" | ||||
|  | ||||
| #: paperless_mail/admin.py:27 | ||||
| msgid "" | ||||
| "Paperless will only process mails that match ALL of the filters given below." | ||||
| msgstr "" | ||||
| "Paperless processará somente e-mails que se encaixam em TODOS os filtros " | ||||
| "abaixo." | ||||
|  | ||||
| #: paperless_mail/admin.py:37 | ||||
| msgid "Actions" | ||||
| msgstr "Ações" | ||||
|  | ||||
| #: paperless_mail/admin.py:39 | ||||
| msgid "" | ||||
| "The action applied to the mail. This action is only performed when documents" | ||||
| " were consumed from the mail. Mails without attachments will remain entirely" | ||||
| " untouched." | ||||
| msgstr "" | ||||
| "A ação se aplica ao e-mail. Essa ação só é executada quando documentos foram" | ||||
| " consumidos do e-mail. E-mails sem anexos permanecerão intactos." | ||||
|  | ||||
| #: paperless_mail/admin.py:46 | ||||
| msgid "Metadata" | ||||
| msgstr "Metadados" | ||||
|  | ||||
| #: paperless_mail/admin.py:48 | ||||
| msgid "" | ||||
| "Assign metadata to documents consumed from this rule automatically. If you " | ||||
| "do not assign tags, types or correspondents here, paperless will still " | ||||
| "process all matching rules that you have defined." | ||||
| msgstr "" | ||||
| "Atribua metadados aos documentos consumidos por esta regra automaticamente. " | ||||
| "Se você não atribuir etiquetas, tipos ou correspondentes aqui, paperless " | ||||
| "ainda sim processará todas as regras de detecção que você definiu." | ||||
|  | ||||
| #: paperless_mail/apps.py:9 | ||||
| msgid "Paperless mail" | ||||
| msgstr "Paperless mail" | ||||
|  | ||||
| #: paperless_mail/models.py:11 | ||||
| msgid "mail account" | ||||
| msgstr "conta de e-mail" | ||||
|  | ||||
| #: paperless_mail/models.py:12 | ||||
| msgid "mail accounts" | ||||
| msgstr "contas de e-mail" | ||||
|  | ||||
| #: paperless_mail/models.py:19 | ||||
| msgid "No encryption" | ||||
| msgstr "Sem encriptação" | ||||
|  | ||||
| #: paperless_mail/models.py:20 | ||||
| msgid "Use SSL" | ||||
| msgstr "Usar SSL" | ||||
|  | ||||
| #: paperless_mail/models.py:21 | ||||
| msgid "Use STARTTLS" | ||||
| msgstr "Usar STARTTLS" | ||||
|  | ||||
| #: paperless_mail/models.py:29 | ||||
| msgid "IMAP server" | ||||
| msgstr "Servidor IMAP" | ||||
|  | ||||
| #: paperless_mail/models.py:33 | ||||
| msgid "IMAP port" | ||||
| msgstr "Porta IMAP" | ||||
|  | ||||
| #: paperless_mail/models.py:36 | ||||
| msgid "" | ||||
| "This is usually 143 for unencrypted and STARTTLS connections, and 993 for " | ||||
| "SSL connections." | ||||
| msgstr "" | ||||
| "É geralmente 143 para não encriptado e conexões STARTTLS, e 993 para " | ||||
| "conexões SSL." | ||||
|  | ||||
| #: paperless_mail/models.py:40 | ||||
| msgid "IMAP security" | ||||
| msgstr "segurança IMAP" | ||||
|  | ||||
| #: paperless_mail/models.py:46 | ||||
| msgid "username" | ||||
| msgstr "usuário" | ||||
|  | ||||
| #: paperless_mail/models.py:50 | ||||
| msgid "password" | ||||
| msgstr "senha" | ||||
|  | ||||
| #: paperless_mail/models.py:60 | ||||
| msgid "mail rule" | ||||
| msgstr "regra de e-mail" | ||||
|  | ||||
| #: paperless_mail/models.py:61 | ||||
| msgid "mail rules" | ||||
| msgstr "regras de e-mail" | ||||
|  | ||||
| #: paperless_mail/models.py:67 | ||||
| msgid "Only process attachments." | ||||
| msgstr "Processar somente anexos." | ||||
|  | ||||
| #: paperless_mail/models.py:68 | ||||
| msgid "Process all files, including 'inline' attachments." | ||||
| msgstr "Processar todos os arquivos, incluindo anexos 'inline'." | ||||
|  | ||||
| #: paperless_mail/models.py:78 | ||||
| msgid "Mark as read, don't process read mails" | ||||
| msgstr "Marcar como lido, não processar e-mails lidos" | ||||
|  | ||||
| #: paperless_mail/models.py:79 | ||||
| msgid "Flag the mail, don't process flagged mails" | ||||
| msgstr "Sinalizar o e-mail, não processar e-mails sinalizados" | ||||
|  | ||||
| #: paperless_mail/models.py:80 | ||||
| msgid "Move to specified folder" | ||||
| msgstr "Mover para pasta especificada" | ||||
|  | ||||
| #: paperless_mail/models.py:81 | ||||
| msgid "Delete" | ||||
| msgstr "Excluir" | ||||
|  | ||||
| #: paperless_mail/models.py:88 | ||||
| msgid "Use subject as title" | ||||
| msgstr "Usar assunto como título" | ||||
|  | ||||
| #: paperless_mail/models.py:89 | ||||
| msgid "Use attachment filename as title" | ||||
| msgstr "Usar nome do arquivo anexo como título" | ||||
|  | ||||
| #: paperless_mail/models.py:99 | ||||
| msgid "Do not assign a correspondent" | ||||
| msgstr "Não atribuir um correspondente" | ||||
|  | ||||
| #: paperless_mail/models.py:101 | ||||
| msgid "Use mail address" | ||||
| msgstr "Usar endereço de e-mail" | ||||
|  | ||||
| #: paperless_mail/models.py:103 | ||||
| msgid "Use name (or mail address if not available)" | ||||
| msgstr "Usar nome (ou endereço de e-mail se não disponível)" | ||||
|  | ||||
| #: paperless_mail/models.py:105 | ||||
| msgid "Use correspondent selected below" | ||||
| msgstr "Usar correspondente selecionado abaixo" | ||||
|  | ||||
| #: paperless_mail/models.py:113 | ||||
| msgid "order" | ||||
| msgstr "ordem" | ||||
|  | ||||
| #: paperless_mail/models.py:120 | ||||
| msgid "account" | ||||
| msgstr "conta" | ||||
|  | ||||
| #: paperless_mail/models.py:124 | ||||
| msgid "folder" | ||||
| msgstr "pasta" | ||||
|  | ||||
| #: paperless_mail/models.py:128 | ||||
| msgid "filter from" | ||||
| msgstr "filtrar de" | ||||
|  | ||||
| #: paperless_mail/models.py:131 | ||||
| msgid "filter subject" | ||||
| msgstr "filtrar assunto" | ||||
|  | ||||
| #: paperless_mail/models.py:134 | ||||
| msgid "filter body" | ||||
| msgstr "filtrar corpo" | ||||
|  | ||||
| #: paperless_mail/models.py:138 | ||||
| msgid "filter attachment filename" | ||||
| msgstr "filtrar nome do arquivo anexo" | ||||
|  | ||||
| #: paperless_mail/models.py:140 | ||||
| msgid "" | ||||
| "Only consume documents which entirely match this filename if specified. " | ||||
| "Wildcards such as *.pdf or *invoice* are allowed. Case insensitive." | ||||
| msgstr "" | ||||
| "Consumir somente documentos que correspondem a este nome de arquivo se especificado.\n" | ||||
| "Curingas como *.pdf ou *invoice* são permitidos. Sem diferenciação de maiúsculas e minúsculas." | ||||
|  | ||||
| #: paperless_mail/models.py:146 | ||||
| msgid "maximum age" | ||||
| msgstr "idade máxima" | ||||
|  | ||||
| #: paperless_mail/models.py:148 | ||||
| msgid "Specified in days." | ||||
| msgstr "Especificada em dias." | ||||
|  | ||||
| #: paperless_mail/models.py:151 | ||||
| msgid "attachment type" | ||||
| msgstr "tipo de anexo" | ||||
|  | ||||
| #: paperless_mail/models.py:154 | ||||
| msgid "" | ||||
| "Inline attachments include embedded images, so it's best to combine this " | ||||
| "option with a filename filter." | ||||
| msgstr "" | ||||
| "Anexos inline incluem imagens inseridas, por isso é melhor combinar essa " | ||||
| "opção com um filtro de nome de arquivo." | ||||
|  | ||||
| #: paperless_mail/models.py:159 | ||||
| msgid "action" | ||||
| msgstr "ação" | ||||
|  | ||||
| #: paperless_mail/models.py:165 | ||||
| msgid "action parameter" | ||||
| msgstr "parâmetro da ação" | ||||
|  | ||||
| #: paperless_mail/models.py:167 | ||||
| msgid "" | ||||
| "Additional parameter for the action selected above, i.e., the target folder " | ||||
| "of the move to folder action." | ||||
| msgstr "" | ||||
| "Parâmetro adicional para a ação selecionada acima, por exemplo: a pasta de " | ||||
| "destino da ação de mover pasta." | ||||
|  | ||||
| #: paperless_mail/models.py:173 | ||||
| msgid "assign title from" | ||||
| msgstr "atribuir título de" | ||||
|  | ||||
| #: paperless_mail/models.py:183 | ||||
| msgid "assign this tag" | ||||
| msgstr "atribuir esta etiqueta" | ||||
|  | ||||
| #: paperless_mail/models.py:191 | ||||
| msgid "assign this document type" | ||||
| msgstr "atribuir este tipo de documento" | ||||
|  | ||||
| #: paperless_mail/models.py:195 | ||||
| msgid "assign correspondent from" | ||||
| msgstr "atribuir correspondente de" | ||||
|  | ||||
| #: paperless_mail/models.py:205 | ||||
| msgid "assign this correspondent" | ||||
| msgstr "atribuir este correspondente" | ||||
| @@ -112,7 +112,10 @@ REST_FRAMEWORK = { | ||||
|         'rest_framework.authentication.BasicAuthentication', | ||||
|         'rest_framework.authentication.SessionAuthentication', | ||||
|         'rest_framework.authentication.TokenAuthentication' | ||||
|     ] | ||||
|     ], | ||||
|     'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning', | ||||
|     'DEFAULT_VERSION': '1', | ||||
|     'ALLOWED_VERSIONS': ['1', '2'] | ||||
| } | ||||
|  | ||||
| if DEBUG: | ||||
| @@ -142,7 +145,7 @@ ASGI_APPLICATION = "paperless.asgi.application" | ||||
|  | ||||
| STATIC_URL = os.getenv("PAPERLESS_STATIC_URL", "/static/") | ||||
|  | ||||
| # what is this used for? | ||||
| # TODO: what is this used for? | ||||
| TEMPLATES = [ | ||||
|     { | ||||
|         'BACKEND': 'django.template.backends.django.DjangoTemplates', | ||||
| @@ -292,7 +295,8 @@ LANGUAGES = [ | ||||
|     ("en-gb", _("English (GB)")), | ||||
|     ("de", _("German")), | ||||
|     ("nl-nl", _("Dutch")), | ||||
|     ("fr", _("French")) | ||||
|     ("fr", _("French")), | ||||
|     ("pt-br", _("Portuguese (Brazil)")) | ||||
| ] | ||||
|  | ||||
| LOCALE_PATHS = [ | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| __version__ = (1, 2, 0) | ||||
| __version__ = (1, 2, 1) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 jonaswinkler
					jonaswinkler