Merge pull request #699 from eikek/small-improvements

Small improvements
This commit is contained in:
mergify[bot] 2021-03-10 23:13:27 +00:00 committed by GitHub
commit 2e9b948d37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 700 additions and 243 deletions

View File

@ -45,12 +45,6 @@ val sharedSettings = Seq(
(scalacOptions.value.filter(o => !o.contains("-Xlint") && !o.contains("-W")))
) ++ scalafixSettings
val testSettings = Seq(
testFrameworks += new TestFramework("minitest.runner.Framework"),
libraryDependencies ++= Dependencies.miniTest ++ Dependencies.logging.map(_ % Test),
Test / fork := true
)
val testSettingsMUnit = Seq(
libraryDependencies ++= Dependencies.munit.map(_ % Test),
testFrameworks += new TestFramework("munit.Framework")
@ -219,6 +213,12 @@ val openapiScalaSettings = Seq(
case "personuse" =>
field =>
field.copy(typeDef = TypeDef("PersonUse", Imports("docspell.common.PersonUse")))
case "orguse" =>
field =>
field.copy(typeDef = TypeDef("OrgUse", Imports("docspell.common.OrgUse")))
case "equipmentuse" =>
field =>
field.copy(typeDef = TypeDef("EquipmentUse", Imports("docspell.common.EquipmentUse")))
}))
)
@ -231,7 +231,7 @@ val common = project
.in(file("modules/common"))
.disablePlugins(RevolverPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(
name := "docspell-common",
libraryDependencies ++=
@ -249,7 +249,7 @@ val files = project
.in(file("modules/files"))
.disablePlugins(RevolverPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(
name := "docspell-files",
libraryDependencies ++=
@ -308,7 +308,7 @@ val store = project
.in(file("modules/store"))
.disablePlugins(RevolverPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(
name := "docspell-store",
libraryDependencies ++=
@ -330,7 +330,7 @@ val extract = project
.in(file("modules/extract"))
.disablePlugins(RevolverPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(
name := "docspell-extract",
libraryDependencies ++=
@ -347,7 +347,7 @@ val convert = project
.in(file("modules/convert"))
.disablePlugins(RevolverPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(
name := "docspell-convert",
libraryDependencies ++=
@ -361,7 +361,7 @@ val analysis = project
.disablePlugins(RevolverPlugin)
.enablePlugins(NerModelsPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(NerModelsPlugin.nerClassifierSettings)
.settings(
name := "docspell-analysis",
@ -375,7 +375,7 @@ val ftsclient = project
.in(file("modules/fts-client"))
.disablePlugins(RevolverPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(
name := "docspell-fts-client",
libraryDependencies ++= Seq.empty
@ -386,7 +386,7 @@ val ftssolr = project
.in(file("modules/fts-solr"))
.disablePlugins(RevolverPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(
name := "docspell-fts-solr",
libraryDependencies ++=
@ -402,7 +402,7 @@ val restapi = project
.disablePlugins(RevolverPlugin)
.enablePlugins(OpenApiSchema)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(openapiScalaSettings)
.settings(
name := "docspell-restapi",
@ -420,7 +420,7 @@ val joexapi = project
.disablePlugins(RevolverPlugin)
.enablePlugins(OpenApiSchema)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(openapiScalaSettings)
.settings(
name := "docspell-joexapi",
@ -438,7 +438,7 @@ val backend = project
.in(file("modules/backend"))
.disablePlugins(RevolverPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(
name := "docspell-backend",
libraryDependencies ++=
@ -473,7 +473,7 @@ val joex = project
.in(file("modules/joex"))
.enablePlugins(BuildInfoPlugin, JavaServerAppPackaging, DebianPlugin, SystemdPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(debianSettings("docspell-joex"))
.settings(buildInfoSettings)
.settings(
@ -512,7 +512,7 @@ val restserver = project
.in(file("modules/restserver"))
.enablePlugins(BuildInfoPlugin, JavaServerAppPackaging, DebianPlugin, SystemdPlugin)
.settings(sharedSettings)
.settings(testSettings)
.settings(testSettingsMUnit)
.settings(debianSettings("docspell-server"))
.settings(buildInfoSettings)
.settings(
@ -740,7 +740,8 @@ def packageTools(logger: Logger, dir: File, version: String): Seq[File] = {
wx / "icons" / "logo-96.png" -> "icons/logo-96.png",
wx / "manifest.json" -> "manifest.json"
),
webext
webext,
None
)
val excludes = Seq(wx, target)
@ -757,7 +758,8 @@ def packageTools(logger: Logger, dir: File, version: String): Seq[File] = {
wx / "native/app_manifest.json" -> s"docspell-tools-${version}/firefox/native/app_manifest.json",
wx / "native/native.py" -> s"docspell-tools-${version}/firefox/native/native.py"
) ++ files,
archive
archive,
None
)
Seq(archive)

View File

@ -1,6 +1,6 @@
package docspell.analysis.classifier
import minitest._
import munit._
import cats.effect._
import scala.concurrent.ExecutionContext
import java.nio.file.Paths
@ -10,7 +10,7 @@ import fs2.Stream
import cats.data.Kleisli
import TextClassifier.Data
object StanfordTextClassifierSuite extends SimpleTestSuite {
class StanfordTextClassifierSuite extends FunSuite {
val logger = Logger.log4s[IO](org.log4s.getLogger)
implicit val CS = IO.contextShift(ExecutionContext.global)

View File

@ -1,9 +1,9 @@
package docspell.analysis.contact
import docspell.common.{NerLabel, NerTag}
import minitest.SimpleTestSuite
import munit._
object ContactAnnotateSpec extends SimpleTestSuite {
class ContactAnnotateSpec extends FunSuite {
test("find email") {

View File

@ -1,11 +1,11 @@
package docspell.analysis.date
import docspell.files.TestFiles
import minitest.SimpleTestSuite
import munit._
import docspell.common._
import java.time._
object DateFindSpec extends SimpleTestSuite {
class DateFindSpec extends FunSuite {
test("find simple dates") {
val expect = Vector(

View File

@ -2,19 +2,17 @@ package docspell.analysis.nlp
import docspell.analysis.Env
import docspell.common.Language.NLPLanguage
import minitest.SimpleTestSuite
import munit._
import docspell.files.TestFiles
import docspell.common._
object BaseCRFAnnotatorSuite extends SimpleTestSuite {
class BaseCRFAnnotatorSuite extends FunSuite {
def annotate(language: NLPLanguage): String => Vector[NerLabel] =
BasicCRFAnnotator.nerAnnotate(BasicCRFAnnotator.Cache.getAnnotator(language))
test("find english ner labels") {
if (Env.isCI) {
ignore("Test ignored on travis.")
}
assume(!Env.isCI, "Test ignored on travis.")
val labels = annotate(Language.English)(TestFiles.letterENText)
val expect = Vector(
@ -52,9 +50,7 @@ object BaseCRFAnnotatorSuite extends SimpleTestSuite {
}
test("find german ner labels") {
if (Env.isCI) {
ignore("Test ignored on travis.")
}
assume(!Env.isCI, "Test ignored on travis.")
val labels = annotate(Language.German)(TestFiles.letterDEText)
val expect = Vector(

View File

@ -4,22 +4,20 @@ import java.nio.file.Paths
import cats.effect.IO
import docspell.analysis.Env
import minitest.SimpleTestSuite
import munit._
import docspell.files.TestFiles
import docspell.common._
import docspell.common.syntax.FileSyntax._
import edu.stanford.nlp.pipeline.StanfordCoreNLP
object StanfordNerAnnotatorSuite extends SimpleTestSuite {
class StanfordNerAnnotatorSuite extends FunSuite {
lazy val germanClassifier =
new StanfordCoreNLP(Properties.nerGerman(None, false))
lazy val englishClassifier =
new StanfordCoreNLP(Properties.nerEnglish(None))
test("find english ner labels") {
if (Env.isCI) {
ignore("Test ignored on travis.")
}
assume(!Env.isCI, "Test ignored on travis.")
val labels =
StanfordNerAnnotator.nerAnnotate(englishClassifier, TestFiles.letterENText)
@ -58,9 +56,7 @@ object StanfordNerAnnotatorSuite extends SimpleTestSuite {
}
test("find german ner labels") {
if (Env.isCI) {
ignore("Test ignored on travis.")
}
assume(!Env.isCI, "Test ignored on travis.")
val labels =
StanfordNerAnnotator.nerAnnotate(germanClassifier, TestFiles.letterDEText)
@ -83,9 +79,7 @@ object StanfordNerAnnotatorSuite extends SimpleTestSuite {
}
test("regexner-only annotator") {
if (Env.isCI) {
ignore("Test ignored on travis.")
}
assume(!Env.isCI, "Test ignored on travis.")
val regexNerContent =
s"""(?i)volantino ag${"\t"}ORGANIZATION${"\t"}LOCATION,PERSON,MISC${"\t"}3

View File

@ -1,8 +1,8 @@
package docspell.analysis.split
import minitest.SimpleTestSuite
import munit._
object TestSplitterSpec extends SimpleTestSuite {
class TestSplitterSpec extends FunSuite {
test("simple splitting") {
val text = """hiermit kündige ich meine Mitgliedschaft in der Kranken- und

View File

@ -0,0 +1,46 @@
package docspell.common
import cats.data.NonEmptyList
import io.circe.Decoder
import io.circe.Encoder
sealed trait EquipmentUse { self: Product =>
final def name: String =
self.productPrefix.toLowerCase()
}
object EquipmentUse {
case object Concerning extends EquipmentUse
case object Disabled extends EquipmentUse
def concerning: EquipmentUse = Concerning
def disabled: EquipmentUse = Disabled
val all: NonEmptyList[EquipmentUse] =
NonEmptyList.of(concerning, disabled)
val notDisabled: NonEmptyList[EquipmentUse] =
NonEmptyList.of(concerning)
def fromString(str: String): Either[String, EquipmentUse] =
str.toLowerCase() match {
case "concerning" =>
Right(Concerning)
case "disabled" =>
Right(Disabled)
case _ =>
Left(s"Unknown equipment-use: $str")
}
def unsafeFromString(str: String): EquipmentUse =
fromString(str).fold(sys.error, identity)
implicit val jsonDecoder: Decoder[EquipmentUse] =
Decoder.decodeString.emap(fromString)
implicit val jsonEncoder: Encoder[EquipmentUse] =
Encoder.encodeString.contramap(_.name)
}

View File

@ -26,7 +26,7 @@ object Ident {
implicit val identEq: Eq[Ident] =
Eq.by(_.id)
val chars: Set[Char] = (('A' to 'Z') ++ ('a' to 'z') ++ ('0' to '9') ++ "-_.").toSet
val chars: Set[Char] = (('A' to 'Z') ++ ('a' to 'z') ++ ('0' to '9') ++ "-_.@").toSet
def randomUUID[F[_]: Sync]: F[Ident] =
Sync[F].delay(unsafe(UUID.randomUUID.toString))

View File

@ -0,0 +1,46 @@
package docspell.common
import cats.data.NonEmptyList
import io.circe.Decoder
import io.circe.Encoder
sealed trait OrgUse { self: Product =>
final def name: String =
self.productPrefix.toLowerCase()
}
object OrgUse {
case object Correspondent extends OrgUse
case object Disabled extends OrgUse
def correspondent: OrgUse = Correspondent
def disabled: OrgUse = Disabled
val all: NonEmptyList[OrgUse] =
NonEmptyList.of(correspondent, disabled)
val notDisabled: NonEmptyList[OrgUse] =
NonEmptyList.of(correspondent)
def fromString(str: String): Either[String, OrgUse] =
str.toLowerCase() match {
case "correspondent" =>
Right(Correspondent)
case "disabled" =>
Right(Disabled)
case _ =>
Left(s"Unknown organization-use: $str")
}
def unsafeFromString(str: String): OrgUse =
fromString(str).fold(sys.error, identity)
implicit val jsonDecoder: Decoder[OrgUse] =
Decoder.decodeString.emap(fromString)
implicit val jsonEncoder: Encoder[OrgUse] =
Encoder.encodeString.contramap(_.name)
}

View File

@ -16,6 +16,7 @@ object PersonUse {
case object Correspondent extends PersonUse
case object Concerning extends PersonUse
case object Both extends PersonUse
case object Disabled extends PersonUse
def concerning: PersonUse = Concerning
def correspondent: PersonUse = Correspondent
@ -35,6 +36,8 @@ object PersonUse {
Right(Concerning)
case "both" =>
Right(Both)
case "disabled" =>
Right(Disabled)
case _ =>
Left(s"Unknown person-use: $str")
}

View File

@ -1,8 +1,8 @@
package docspell.common
import minitest._
import munit._
object FileNameTest extends SimpleTestSuite {
class FileNameTest extends FunSuite {
test("make filename") {
val data = List(

View File

@ -1,9 +1,9 @@
package docspell.common
import minitest._
import munit._
import Glob._
object GlobTest extends SimpleTestSuite {
class GlobTest extends FunSuite {
test("literals") {
assert(Glob.pattern(Pattern(Segment(Token.Literal("hello")))).matches(true)("hello"))

View File

@ -1,10 +1,10 @@
package docspell.common
import minitest._
import munit._
import cats.data.NonEmptyList
import docspell.common.MetaProposal.Candidate
object MetaProposalListTest extends SimpleTestSuite {
class MetaProposalListTest extends FunSuite {
test("flatten retains order of candidates") {
val cand1 = Candidate(IdRef(Ident.unsafe("123"), "name"), Set.empty)

View File

@ -1,8 +1,8 @@
package docspell.common
import minitest._
import munit._
object NerLabelSpanTest extends SimpleTestSuite {
class NerLabelSpanTest extends FunSuite {
test("build") {
val labels = List(

View File

@ -11,10 +11,10 @@ import docspell.convert.ConversionResult.Handler
import docspell.convert.extern.{TesseractConfig, UnoconvConfig, WkHtmlPdfConfig}
import docspell.convert.flexmark.MarkdownConfig
import docspell.files.{ExampleFiles, TestFiles}
import minitest.SimpleTestSuite
import munit._
import docspell.convert.extern.OcrMyPdfConfig
object ConversionTest extends SimpleTestSuite with FileChecks {
class ConversionTest extends FunSuite with FileChecks {
val blocker = TestFiles.blocker
implicit val CS = TestFiles.CS
@ -101,8 +101,8 @@ object ConversionTest extends SimpleTestSuite with FileChecks {
)
test("convert to pdf") {
if (!commandsExist) ignore("At least one of the conversion programs not found")
else
assume(commandsExist, "At least one of the conversion programs not found")
File
.withTempDir[IO](target, "convpdf")
.use { dir =>
@ -119,8 +119,7 @@ object ConversionTest extends SimpleTestSuite with FileChecks {
}
test("convert image to pdf and txt") {
if (!commandsExist) ignore("At least one of the conversion programs not found")
else
assume(commandsExist, "At least one of the conversion programs not found")
File
.withTempDir[IO](target, "convimgpdf")
.use { dir =>
@ -139,8 +138,8 @@ object ConversionTest extends SimpleTestSuite with FileChecks {
}
test("do not convert image bombs") {
if (!commandsExist) ignore("At least one of the conversion programs not found")
else
assume(commandsExist, "At least one of the conversion programs not found")
conversion
.use { conv =>
def check: Handler[IO, Unit] =

View File

@ -6,10 +6,10 @@ import cats.effect._
import docspell.common._
import docspell.convert._
import docspell.files.{ExampleFiles, TestFiles}
import minitest.SimpleTestSuite
import munit._
import java.nio.charset.StandardCharsets
object ExternConvTest extends SimpleTestSuite with FileChecks {
class ExternConvTest extends FunSuite with FileChecks {
val blocker = TestFiles.blocker
implicit val CS = TestFiles.CS
val utf8 = StandardCharsets.UTF_8
@ -22,9 +22,7 @@ object ExternConvTest extends SimpleTestSuite with FileChecks {
Seq("-s", "A4", "--encoding", "UTF-8", "-", "{{outfile}}"),
Duration.seconds(20)
)
if (!commandExists(cfg.program)) ignore(s"Command ${cfg.program} not found")
else
assume(commandExists(cfg.program), s"Command ${cfg.program} not found. Ignore tests.")
File
.withTempDir[IO](target, "wkhtmltopdf")
.use(dir =>
@ -51,8 +49,7 @@ object ExternConvTest extends SimpleTestSuite with FileChecks {
Duration.seconds(20)
)
if (!commandExists(cfg.program)) ignore(s"Command ${cfg.program} not found")
else
assume(commandExists(cfg.program), s"Command ${cfg.program} not found. Ignore tests.")
File
.withTempDir[IO](target, "unoconv")
.use(dir =>
@ -78,9 +75,7 @@ object ExternConvTest extends SimpleTestSuite with FileChecks {
Seq("{{infile}}", "out", "-l", "deu", "pdf", "txt"),
Duration.seconds(20)
)
if (!commandExists(cfg.program)) ignore(s"Command ${cfg.program} not found")
else
assume(commandExists(cfg.program), s"Command ${cfg.program} not found")
File
.withTempDir[IO](target, "tesseract")
.use(dir =>

View File

@ -3,15 +3,14 @@ package docspell.extract.ocr
import cats.effect.IO
import docspell.common.Logger
import docspell.files.TestFiles
import minitest.SimpleTestSuite
import munit._
object TextExtractionSuite extends SimpleTestSuite {
class TextExtractionSuite extends FunSuite {
import TestFiles._
val logger = Logger.log4s[IO](org.log4s.getLogger)
test("extract english pdf") {
ignore()
test("extract english pdf".ignore) {
val text = TextExtract
.extract[IO](letterSourceEN, blocker, logger, "eng", OcrConfig.default)
.compile
@ -20,8 +19,7 @@ object TextExtractionSuite extends SimpleTestSuite {
println(text)
}
test("extract german pdf") {
ignore()
test("extract german pdf".ignore) {
val expect = TestFiles.letterDEText
val extract = TextExtract
.extract[IO](letterSourceDE, blocker, logger, "deu", OcrConfig.default)

View File

@ -2,9 +2,9 @@ package docspell.extract.odf
import cats.effect._
import docspell.files.{ExampleFiles, TestFiles}
import minitest.SimpleTestSuite
import munit._
object OdfExtractTest extends SimpleTestSuite {
class OdfExtractTest extends FunSuite {
val blocker = TestFiles.blocker
implicit val CS = TestFiles.CS

View File

@ -1,8 +1,8 @@
package docspell.extract.pdfbox
import minitest.SimpleTestSuite
import munit._
object PdfMetaDataTest extends SimpleTestSuite {
class PdfMetaDataTest extends FunSuite {
test("split keywords on comma") {
val md = PdfMetaData.empty.copy(keywords = Some("a,b, c"))

View File

@ -2,9 +2,9 @@ package docspell.extract.pdfbox
import cats.effect._
import docspell.files.{ExampleFiles, TestFiles}
import minitest.SimpleTestSuite
import munit._
object PdfboxExtractTest extends SimpleTestSuite {
class PdfboxExtractTest extends FunSuite {
val blocker = TestFiles.blocker
implicit val CS = TestFiles.CS

View File

@ -2,11 +2,11 @@ package docspell.extract.pdfbox
import cats.effect._
import docspell.files.{ExampleFiles, TestFiles}
import minitest.SimpleTestSuite
import munit._
import java.nio.file.Path
import fs2.Stream
object PdfboxPreviewTest extends SimpleTestSuite {
class PdfboxPreviewTest extends FunSuite {
val blocker = TestFiles.blocker
implicit val CS = TestFiles.CS

View File

@ -3,9 +3,9 @@ package docspell.extract.poi
import cats.effect._
import docspell.common.MimeTypeHint
import docspell.files.{ExampleFiles, TestFiles}
import minitest.SimpleTestSuite
import munit._
object PoiExtractTest extends SimpleTestSuite {
class PoiExtractTest extends FunSuite {
val blocker = TestFiles.blocker
implicit val CS = TestFiles.CS

View File

@ -1,9 +1,9 @@
package docspell.extract.rtf
import docspell.files.ExampleFiles
import minitest.SimpleTestSuite
import munit._
object RtfExtractTest extends SimpleTestSuite {
class RtfExtractTest extends FunSuite {
test("extract text from rtf using java input-stream") {
val file = ExampleFiles.examples_sample_rtf

View File

@ -2,12 +2,12 @@ package docspell.files
import cats.implicits._
import cats.effect.{Blocker, IO}
import minitest.SimpleTestSuite
import munit._
import scala.concurrent.ExecutionContext
import scala.util.Using
object ImageSizeTest extends SimpleTestSuite {
class ImageSizeTest extends FunSuite {
val blocker = Blocker.liftExecutionContext(ExecutionContext.global)
implicit val CS = IO.contextShift(ExecutionContext.global)

View File

@ -1,12 +1,12 @@
package docspell.files
import minitest._
import munit._
import cats.effect._
import cats.implicits._
import scala.concurrent.ExecutionContext
import docspell.common.Glob
object ZipTest extends SimpleTestSuite {
class ZipTest extends FunSuite {
val blocker = Blocker.liftExecutionContext(ExecutionContext.global)
implicit val CS = IO.contextShift(ExecutionContext.global)

View File

@ -47,7 +47,7 @@ object FindProposal {
ctx.store
.transact(
ROrganization
.findLike(coll, mp.values.head.ref.name.toLowerCase)
.findLike(coll, mp.values.head.ref.name.toLowerCase, OrgUse.notDisabled)
.map(_.headOption)
)
.flatTap(oref =>
@ -85,7 +85,11 @@ object FindProposal {
ctx.store
.transact(
REquipment
.findLike(coll, mp.values.head.ref.name.toLowerCase)
.findLike(
coll,
mp.values.head.ref.name.toLowerCase,
EquipmentUse.notDisabled
)
.map(_.headOption)
)
.flatTap(oref =>
@ -234,7 +238,10 @@ object FindProposal {
case NerTag.Organization =>
ctx.logger.debug(s"Looking for organizations: $value") *>
ctx.store
.transact(ROrganization.findLike(ctx.args.meta.collective, value))
.transact(
ROrganization
.findLike(ctx.args.meta.collective, value, OrgUse.notDisabled)
)
.map(MetaProposalList.from(MetaProposalType.CorrOrg, nt))
case NerTag.Person =>
@ -252,7 +259,10 @@ object FindProposal {
.map(MetaProposalList.from(MetaProposalType.CorrPerson, nt))
val s3 =
ctx.store
.transact(ROrganization.findLike(ctx.args.meta.collective, value))
.transact(
ROrganization
.findLike(ctx.args.meta.collective, value, OrgUse.notDisabled)
)
.map(MetaProposalList.from(MetaProposalType.CorrOrg, nt))
ctx.logger.debug(s"Looking for persons and organizations: $value") *> (for {
ml0 <- s1
@ -268,7 +278,10 @@ object FindProposal {
case NerTag.Misc =>
ctx.logger.debug(s"Looking for equipments: $value") *>
ctx.store
.transact(REquipment.findLike(ctx.args.meta.collective, value))
.transact(
REquipment
.findLike(ctx.args.meta.collective, value, EquipmentUse.notDisabled)
)
.map(MetaProposalList.from(MetaProposalType.ConcEquip, nt))
case NerTag.Email =>

View File

@ -1,10 +1,10 @@
package docspell.joex.analysis
import minitest._
import munit._
import NerFile.Pattern
import java.{util => ju}
object NerFileTest extends SimpleTestSuite {
class NerFileTest extends FunSuite {
test("create valid case insensitive patterns") {
val names = List(

View File

@ -1,9 +1,9 @@
package docspell.joex.scheduler
import docspell.common.Priority
import minitest.SimpleTestSuite
import munit._
object CountingSchemeSpec extends SimpleTestSuite {
class CountingSchemeSpec extends FunSuite {
test("counting") {
val cs = CountingScheme(2, 1)

View File

@ -5064,6 +5064,7 @@ components:
- id
- name
- created
- use
properties:
id:
type: string
@ -5076,6 +5077,12 @@ components:
format: date-time
notes:
type: string
use:
type: string
format: equipmentuse
enum:
- concerning
- disabled
ReferenceList:
description:
Listing of entities with their id and a name.
@ -5119,6 +5126,7 @@ components:
- concerning
- correspondent
- both
- disabled
description: |
Whether this person should be used to create suggestions
for the "concerning person", "correspondent" or both.
@ -5145,6 +5153,7 @@ components:
- address
- contacts
- created
- use
properties:
id:
type: string
@ -5165,6 +5174,12 @@ components:
format: date-time
shortName:
type: string
use:
type: string
format: orguse
enum:
- correspondent
- disabled
OrganizationList:
description: |
A list of full organization values.

View File

@ -392,7 +392,8 @@ trait Conversions {
v.contacts.map(mkContact).toList,
ro.notes,
ro.created,
ro.shortName
ro.shortName,
ro.use
)
}
@ -414,7 +415,8 @@ trait Conversions {
v.notes,
now,
now,
v.shortName.map(_.trim)
v.shortName.map(_.trim),
v.use
)
} yield OOrganization.OrgAndContacts(org, cont)
}
@ -439,7 +441,8 @@ trait Conversions {
v.notes,
v.created,
now,
v.shortName.map(_.trim)
v.shortName.map(_.trim),
v.use
)
} yield OOrganization.OrgAndContacts(org, cont)
}
@ -628,17 +631,17 @@ trait Conversions {
// equipment
def mkEquipment(re: REquipment): Equipment =
Equipment(re.eid, re.name, re.created, re.notes)
Equipment(re.eid, re.name, re.created, re.notes, re.use)
def newEquipment[F[_]: Sync](e: Equipment, cid: Ident): F[REquipment] =
timeId.map({ case (id, now) =>
REquipment(id, cid, e.name.trim, now, now, e.notes)
REquipment(id, cid, e.name.trim, now, now, e.notes, e.use)
})
def changeEquipment[F[_]: Sync](e: Equipment, cid: Ident): F[REquipment] =
Timestamp
.current[F]
.map(now => REquipment(e.id, cid, e.name.trim, e.created, now, e.notes))
.map(now => REquipment(e.id, cid, e.name.trim, e.created, now, e.notes, e.use))
// idref

View File

@ -18,11 +18,12 @@ case class Flags(
fullTextSearchEnabled: Boolean,
maxPageSize: Int,
maxNoteLength: Int,
showClassificationSettings: Boolean
showClassificationSettings: Boolean,
uiVersion: Int
)
object Flags {
def apply(cfg: Config): Flags =
def apply(cfg: Config, uiVersion: Int): Flags =
Flags(
cfg.appName,
getBaseUrl(cfg),
@ -32,7 +33,8 @@ object Flags {
cfg.fullTextSearch.enabled,
cfg.maxItemPageSize,
cfg.maxNoteLength,
cfg.showClassificationSettings
cfg.showClassificationSettings,
uiVersion
)
private def getBaseUrl(cfg: Config): String =

View File

@ -133,10 +133,11 @@ object TemplateRoutes {
)
object IndexData {
private[this] val uiVersion = 2
def apply(cfg: Config): IndexData =
IndexData(
Flags(cfg),
Flags(cfg, uiVersion),
chooseUi,
Seq(
"/app/assets" + Webjars.clipboardjs + "/clipboard.min.js",
@ -145,7 +146,7 @@ object TemplateRoutes {
),
s"/app/assets/docspell-webapp/${BuildInfo.version}/favicon",
s"/app/assets/docspell-webapp/${BuildInfo.version}/docspell.js",
Flags(cfg).asJson.spaces2
Flags(cfg, uiVersion).asJson.spaces2
)
private def chooseUi: Seq[String] =

View File

@ -0,0 +1,16 @@
ALTER TABLE "equipment"
ADD COLUMN "equip_use" varchar(254);
UPDATE "equipment" SET "equip_use" = 'concerning';
ALTER TABLE "equipment"
ALTER COLUMN "equip_use" SET NOT NULL;
ALTER TABLE "organization"
ADD COLUMN "org_use" varchar(254);
UPDATE "organization" SET "org_use" = 'correspondent';
ALTER TABLE "organization"
ALTER COLUMN "org_use" SET NOT NULL;

View File

@ -0,0 +1,16 @@
ALTER TABLE `equipment`
ADD COLUMN `equip_use` varchar(254);
UPDATE `equipment` SET `equip_use` = 'concerning';
ALTER TABLE `equipment`
ALTER COLUMN `equip_use` SET NOT NULL;
ALTER TABLE `organization`
ADD COLUMN `org_use` varchar(254);
UPDATE `organization` SET `org_use` = 'correspondent';
ALTER TABLE `organization`
ALTER COLUMN `org_use` SET NOT NULL;

View File

@ -0,0 +1,16 @@
ALTER TABLE "equipment"
ADD COLUMN "equip_use" varchar(254);
UPDATE "equipment" SET "equip_use" = 'concerning';
ALTER TABLE "equipment"
ALTER COLUMN "equip_use" SET NOT NULL;
ALTER TABLE "organization"
ADD COLUMN "org_use" varchar(254);
UPDATE "organization" SET "org_use" = 'correspondent';
ALTER TABLE "organization"
ALTER COLUMN "org_use" SET NOT NULL;

View File

@ -106,6 +106,12 @@ trait DoobieMeta extends EmilDoobieMeta {
implicit val metaPersonUse: Meta[PersonUse] =
Meta[String].timap(PersonUse.unsafeFromString)(_.name)
implicit val metaEquipUse: Meta[EquipmentUse] =
Meta[String].timap(EquipmentUse.unsafeFromString)(_.name)
implicit val metaOrgUse: Meta[OrgUse] =
Meta[String].timap(OrgUse.unsafeFromString)(_.name)
}
object DoobieMeta extends DoobieMeta {

View File

@ -15,7 +15,8 @@ case class REquipment(
name: String,
created: Timestamp,
updated: Timestamp,
notes: Option[String]
notes: Option[String],
use: EquipmentUse
) {}
object REquipment {
@ -28,7 +29,8 @@ object REquipment {
val created = Column[Timestamp]("created", this)
val updated = Column[Timestamp]("updated", this)
val notes = Column[String]("notes", this)
val all = NonEmptyList.of[Column[_]](eid, cid, name, created, updated, notes)
val use = Column[EquipmentUse]("equip_use", this)
val all = NonEmptyList.of[Column[_]](eid, cid, name, created, updated, notes, use)
}
val T = Table(None)
@ -41,7 +43,7 @@ object REquipment {
.insert(
t,
t.all,
fr"${v.eid},${v.cid},${v.name},${v.created},${v.updated},${v.notes}"
fr"${v.eid},${v.cid},${v.name},${v.created},${v.updated},${v.notes},${v.use}"
)
}
@ -57,7 +59,8 @@ object REquipment {
t.cid.setTo(v.cid),
t.name.setTo(v.name),
t.updated.setTo(now),
t.notes.setTo(v.notes)
t.notes.setTo(v.notes),
t.use.setTo(v.use)
)
)
} yield n
@ -90,9 +93,17 @@ object REquipment {
sql.query[REquipment].to[Vector]
}
def findLike(coll: Ident, equipName: String): ConnectionIO[Vector[IdRef]] = {
def findLike(
coll: Ident,
equipName: String,
use: NonEmptyList[EquipmentUse]
): ConnectionIO[Vector[IdRef]] = {
val t = Table(None)
run(select(t.eid, t.name), from(t), t.cid === coll && t.name.like(equipName))
run(
select(t.eid, t.name),
from(t),
t.cid === coll && t.name.like(equipName) && t.use.in(use)
)
.query[IdRef]
.to[Vector]
}

View File

@ -22,7 +22,8 @@ case class ROrganization(
notes: Option[String],
created: Timestamp,
updated: Timestamp,
shortName: Option[String]
shortName: Option[String],
use: OrgUse
) {}
object ROrganization {
@ -43,6 +44,7 @@ object ROrganization {
val created = Column[Timestamp]("created", this)
val updated = Column[Timestamp]("updated", this)
val shortName = Column[String]("short_name", this)
val use = Column[OrgUse]("org_use", this)
val all =
NonEmptyList.of[Column[_]](
oid,
@ -55,7 +57,8 @@ object ROrganization {
notes,
created,
updated,
shortName
shortName,
use
)
}
@ -67,7 +70,7 @@ object ROrganization {
DML.insert(
T,
T.all,
fr"${v.oid},${v.cid},${v.name},${v.street},${v.zip},${v.city},${v.country},${v.notes},${v.created},${v.updated},${v.shortName}"
fr"${v.oid},${v.cid},${v.name},${v.street},${v.zip},${v.city},${v.country},${v.notes},${v.created},${v.updated},${v.shortName},${v.use}"
)
def update(v: ROrganization): ConnectionIO[Int] = {
@ -84,7 +87,8 @@ object ROrganization {
T.country.setTo(v.country),
T.notes.setTo(v.notes),
T.updated.setTo(now),
T.shortName.setTo(v.shortName)
T.shortName.setTo(v.shortName),
T.use.setTo(v.use)
)
)
for {
@ -109,11 +113,17 @@ object ROrganization {
sql.query[ROrganization].option
}
def findLike(coll: Ident, orgName: String): ConnectionIO[Vector[IdRef]] =
def findLike(
coll: Ident,
orgName: String,
use: NonEmptyList[OrgUse]
): ConnectionIO[Vector[IdRef]] =
run(
select(T.oid, T.name),
from(T),
T.cid === coll && (T.name.like(orgName) || T.shortName.like(orgName))
T.cid === coll && (T.name.like(orgName) || T.shortName.like(orgName)) && T.use.in(
use
)
)
.query[IdRef]
.to[Vector]

View File

@ -3,14 +3,14 @@ package docspell.store.generator
import java.time.LocalDate
import docspell.store.records._
import minitest._
import munit._
import docspell.common._
import docspell.query.ItemQueryParser
import docspell.store.queries.AttachCountTable
import docspell.store.qb.DSL._
import docspell.store.qb.generator.{ItemQueryGenerator, Tables}
object ItemQueryGeneratorTest extends SimpleTestSuite {
class ItemQueryGeneratorTest extends FunSuite {
import docspell.store.impl.DoobieMeta._
val tables = Tables(

View File

@ -1,10 +1,10 @@
package docspell.store.qb
import minitest._
import munit._
import docspell.store.qb.model._
import docspell.store.qb.DSL._
object QueryBuilderTest extends SimpleTestSuite {
class QueryBuilderTest extends FunSuite {
test("simple") {
val c = CourseRecord.as("c")

View File

@ -1,11 +1,11 @@
package docspell.store.qb.impl
import minitest._
import munit._
import docspell.store.qb._
import docspell.store.qb.DSL._
import docspell.store.qb.model.{CourseRecord, PersonRecord}
object ConditionBuilderTest extends SimpleTestSuite {
class ConditionBuilderTest extends FunSuite {
val c = CourseRecord.as("c")
val p = PersonRecord.as("p")

View File

@ -1,11 +1,11 @@
package docspell.store.qb.impl
import minitest._
import munit._
import docspell.store.qb._
import docspell.store.qb.DSL._
import docspell.store.qb.model.{CourseRecord, PersonRecord}
object DSLTest extends SimpleTestSuite {
class DSLTest extends FunSuite {
val course = CourseRecord.as("c")
val person = PersonRecord.as("p")

View File

@ -1,11 +1,11 @@
package docspell.store.qb.impl
import minitest._
import munit._
import docspell.store.qb._
import docspell.store.qb.model._
import docspell.store.qb.DSL._
object SelectBuilderTest extends SimpleTestSuite {
class SelectBuilderTest extends FunSuite {
test("basic fragment") {
val c = CourseRecord.as("c")

View File

@ -1,8 +1,8 @@
package docspell.store.queries
import minitest._
import munit._
object QueryWildcardTest extends SimpleTestSuite {
class QueryWildcardTest extends FunSuite {
test("replace prefix") {
assertEquals("%name", QueryWildcard("*name"))

View File

@ -10,6 +10,8 @@ module Comp.EquipmentForm exposing
import Api.Model.Equipment exposing (Equipment)
import Comp.Basic as B
import Comp.FixedDropdown
import Data.EquipmentUse exposing (EquipmentUse)
import Data.Flags exposing (Flags)
import Html exposing (..)
import Html.Attributes exposing (..)
@ -22,6 +24,8 @@ type alias Model =
{ equipment : Equipment
, name : String
, notes : Maybe String
, use : EquipmentUse
, useModel : Comp.FixedDropdown.Model EquipmentUse
}
@ -30,6 +34,11 @@ emptyModel =
{ equipment = Api.Model.Equipment.empty
, name = ""
, notes = Nothing
, use = Data.EquipmentUse.Concerning
, useModel =
Comp.FixedDropdown.initMap
Data.EquipmentUse.label
Data.EquipmentUse.all
}
@ -44,6 +53,7 @@ getEquipment model =
, name = model.name
, created = model.equipment.created
, notes = model.notes
, use = Data.EquipmentUse.asString model.use
}
@ -51,6 +61,7 @@ type Msg
= SetName String
| SetEquipment Equipment
| SetNotes String
| UseDropdownMsg (Comp.FixedDropdown.Msg EquipmentUse)
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
@ -61,6 +72,9 @@ update _ msg model =
| equipment = t
, name = t.name
, notes = t.notes
, use =
Data.EquipmentUse.fromString t.use
|> Maybe.withDefault Data.EquipmentUse.Concerning
}
, Cmd.none
)
@ -71,6 +85,16 @@ update _ msg model =
SetNotes str ->
( { model | notes = Util.Maybe.fromString str }, Cmd.none )
UseDropdownMsg lm ->
let
( nm, mu ) =
Comp.FixedDropdown.update lm model.useModel
newUse =
Maybe.withDefault model.use mu
in
( { model | useModel = nm, use = newUse }, Cmd.none )
--- View2
@ -102,6 +126,22 @@ view2 model =
]
[]
]
, div [ class "mb-4" ]
[ label
[ class S.inputLabel
]
[ text "Use" ]
, Html.map UseDropdownMsg
(Comp.FixedDropdown.view2 (makeUseItem model) model.useModel)
, span [ class "opacity-50 text-sm" ]
[ case model.use of
Data.EquipmentUse.Concerning ->
text "Use as concerning equipment"
Data.EquipmentUse.Disabled ->
text "Do not use for suggestions."
]
]
, div [ class "mb-4" ]
[ h3 [ class S.header3 ]
[ text "Notes"
@ -116,3 +156,9 @@ view2 model =
]
]
]
makeUseItem : Model -> Maybe (Comp.FixedDropdown.Item EquipmentUse)
makeUseItem model =
Just <|
Comp.FixedDropdown.Item model.use (Data.EquipmentUse.label model.use)

View File

@ -8,6 +8,7 @@ module Comp.EquipmentTable exposing
import Api.Model.Equipment exposing (Equipment)
import Comp.Basic as B
import Data.EquipmentUse
import Data.Flags exposing (Flags)
import Html exposing (..)
import Html.Attributes exposing (..)
@ -57,6 +58,9 @@ view2 model =
[ thead []
[ tr []
[ th [ class "" ] []
, th [ class "text-left pr-1 md:px-2 w-20" ]
[ text "Use"
]
, th [ class "text-left" ] [ text "Name" ]
]
]
@ -72,6 +76,14 @@ renderEquipmentLine2 model equip =
, class S.tableRow
]
[ B.editLinkTableCell (Select equip)
, td [ class "text-left pr-1 md:px-2" ]
[ div [ class "label inline-flex text-sm" ]
[ Data.EquipmentUse.fromString equip.use
|> Maybe.withDefault Data.EquipmentUse.Concerning
|> Data.EquipmentUse.label
|> text
]
]
, td [ class "text-left" ]
[ text equip.name
]

View File

@ -12,7 +12,9 @@ import Api.Model.Organization exposing (Organization)
import Comp.AddressForm
import Comp.Basic as B
import Comp.ContactField
import Comp.FixedDropdown
import Data.Flags exposing (Flags)
import Data.OrgUse exposing (OrgUse)
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
@ -28,6 +30,8 @@ type alias Model =
, contactModel : Comp.ContactField.Model
, notes : Maybe String
, shortName : Maybe String
, use : OrgUse
, useModel : Comp.FixedDropdown.Model OrgUse
}
@ -39,6 +43,11 @@ emptyModel =
, contactModel = Comp.ContactField.emptyModel
, notes = Nothing
, shortName = Nothing
, use = Data.OrgUse.Correspondent
, useModel =
Comp.FixedDropdown.initMap
Data.OrgUse.label
Data.OrgUse.all
}
@ -59,6 +68,7 @@ getOrg model =
, contacts = Comp.ContactField.getContacts model.contactModel
, notes = model.notes
, shortName = model.shortName
, use = Data.OrgUse.asString model.use
}
@ -69,6 +79,7 @@ type Msg
| ContactMsg Comp.ContactField.Msg
| SetNotes String
| SetShortName String
| UseDropdownMsg (Comp.FixedDropdown.Msg OrgUse)
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
@ -87,6 +98,9 @@ update flags msg model =
, name = t.name
, notes = t.notes
, shortName = t.shortName
, use =
Data.OrgUse.fromString t.use
|> Maybe.withDefault Data.OrgUse.Correspondent
}
, Cmd.batch [ c1, c2 ]
)
@ -118,11 +132,27 @@ update flags msg model =
, Cmd.none
)
UseDropdownMsg lm ->
let
( nm, mu ) =
Comp.FixedDropdown.update lm model.useModel
newUse =
Maybe.withDefault model.use mu
in
( { model | useModel = nm, use = newUse }, Cmd.none )
--- View2
makeUseItem : Model -> Maybe (Comp.FixedDropdown.Item OrgUse)
makeUseItem model =
Just <|
Comp.FixedDropdown.Item model.use (Data.OrgUse.label model.use)
view2 : Bool -> UiSettings -> Model -> Html Msg
view2 mobile settings model =
div [ class "flex flex-col" ]
@ -167,6 +197,22 @@ view2 mobile settings model =
]
[]
]
, div [ class "mb-4" ]
[ label
[ class S.inputLabel
]
[ text "Use" ]
, Html.map UseDropdownMsg
(Comp.FixedDropdown.view2 (makeUseItem model) model.useModel)
, span [ class "opacity-50 text-sm" ]
[ case model.use of
Data.OrgUse.Correspondent ->
text "Use as correspondent"
Data.OrgUse.Disabled ->
text "Do not use for suggestions."
]
]
, div [ class "mb-4" ]
[ h3 [ class S.header3 ]
[ text "Address"

View File

@ -9,6 +9,7 @@ module Comp.OrgTable exposing
import Api.Model.Organization exposing (Organization)
import Comp.Basic as B
import Data.Flags exposing (Flags)
import Data.OrgUse
import Html exposing (..)
import Html.Attributes exposing (..)
import Styles as S
@ -58,6 +59,9 @@ view2 model =
[ thead []
[ tr []
[ th [ class "" ] []
, th [ class "text-left pr-1 md:px-2" ]
[ text "Use"
]
, th [ class "text-left" ] [ text "Name" ]
, th [ class "text-left hidden md:table-cell" ] [ text "Address" ]
, th [ class "text-left hidden sm:table-cell" ] [ text "Contact" ]
@ -75,6 +79,14 @@ renderOrgLine2 model org =
, class S.tableRow
]
[ B.editLinkTableCell (Select org)
, td [ class "text-left pr-1 md:px-2" ]
[ div [ class "label inline-flex text-sm" ]
[ Data.OrgUse.fromString org.use
|> Maybe.withDefault Data.OrgUse.Correspondent
|> Data.OrgUse.label
|> text
]
]
, td [ class "py-4 sm:py-2 pr-2 md:pr-4" ]
[ text org.name
]

View File

@ -229,6 +229,9 @@ view2 mobile settings model =
Data.PersonUse.Both ->
text "Use as both concerning or correspondent person"
Data.PersonUse.Disabled ->
text "Do not use for suggestions."
]
]
, div [ class "mb-4" ]

View File

@ -33,6 +33,7 @@ import Comp.TagSelect
import Data.CustomFieldChange exposing (CustomFieldValueCollect)
import Data.Direction exposing (Direction)
import Data.DropdownStyle as DS
import Data.EquipmentUse
import Data.Fields
import Data.Flags exposing (Flags)
import Data.ItemQuery as Q exposing (ItemQuery)
@ -490,7 +491,11 @@ updateDrop ddm flags settings msg model =
SetConcEquip id ->
let
equip =
Equipment id.id id.name 0 Nothing
Equipment id.id
id.name
0
Nothing
(Data.EquipmentUse.asString Data.EquipmentUse.Concerning)
in
resetAndSet (ConcEquipmentMsg (Comp.Dropdown.SetSelection [ equip ]))

View File

@ -0,0 +1,52 @@
module Data.EquipmentUse exposing
( EquipmentUse(..)
, all
, asString
, fromString
, label
)
import Api.Model.Equipment exposing (Equipment)
type EquipmentUse
= Concerning
| Disabled
fromString : String -> Maybe EquipmentUse
fromString str =
case String.toLower str of
"concerning" ->
Just Concerning
"disabled" ->
Just Disabled
_ ->
Nothing
asString : EquipmentUse -> String
asString pu =
case pu of
Concerning ->
"concerning"
Disabled ->
"disabled"
label : EquipmentUse -> String
label pu =
case pu of
Concerning ->
"Concerning"
Disabled ->
"Disabled"
all : List EquipmentUse
all =
[ Concerning, Disabled ]

View File

@ -0,0 +1,50 @@
module Data.OrgUse exposing
( OrgUse(..)
, all
, asString
, fromString
, label
)
type OrgUse
= Correspondent
| Disabled
fromString : String -> Maybe OrgUse
fromString str =
case String.toLower str of
"correspondent" ->
Just Correspondent
"disabled" ->
Just Disabled
_ ->
Nothing
asString : OrgUse -> String
asString pu =
case pu of
Correspondent ->
"correspondent"
Disabled ->
"disabled"
label : OrgUse -> String
label pu =
case pu of
Correspondent ->
"Correspondent"
Disabled ->
"Disabled"
all : List OrgUse
all =
[ Correspondent, Disabled ]

View File

@ -14,6 +14,7 @@ type PersonUse
= Correspondent
| Concerning
| Both
| Disabled
fromString : String -> Maybe PersonUse
@ -28,6 +29,9 @@ fromString str =
"both" ->
Just Both
"disabled" ->
Just Disabled
_ ->
Nothing
@ -44,6 +48,9 @@ asString pu =
Both ->
"both"
Disabled ->
"disabled"
label : PersonUse -> String
label pu =
@ -57,10 +64,13 @@ label pu =
Both ->
"Both"
Disabled ->
"Disabled"
all : List PersonUse
all =
[ Correspondent, Concerning, Both ]
[ Correspondent, Concerning, Both, Disabled ]
spanPersonList : List Person -> { concerning : List Person, correspondent : List Person }
@ -86,5 +96,8 @@ spanPersonList input =
| correspondent = p :: res.correspondent
, concerning = p :: res.concerning
}
Disabled ->
res
in
List.foldl merge init input

View File

@ -1,9 +1,11 @@
module Page.Register.Update exposing (update)
import Api
import Api.Model.BasicResult exposing (BasicResult)
import Data.Flags exposing (Flags)
import Page exposing (Page(..))
import Page.Register.Data exposing (..)
import Util.Http
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
@ -106,8 +108,16 @@ update flags msg model =
, cmd
)
SubmitResp (Err _) ->
( model, Cmd.none )
SubmitResp (Err err) ->
let
errMsg =
Util.Http.errorToString err
res =
BasicResult False
(errMsg ++ " Please check the form and try again.")
in
( { model | result = Just res }, Cmd.none )
validateForm : Model -> List String

View File

@ -164,12 +164,14 @@ errorToString : Http.Error -> String
errorToString error =
let
f sc =
case sc of
404 ->
if sc == 404 then
"The requested resource doesn't exist."
_ ->
"There was an invalid response status: " ++ String.fromInt sc
else if sc >= 400 && sc < 500 then
"Invalid input when processing the request."
else
"There was an invalid response status: " ++ String.fromInt sc ++ "."
in
errorToStringStatus error f

View File

@ -34,7 +34,7 @@ if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
fi
OPTIONS=c:hsde
LONGOPTS=config:,help,skip,delete,exists
LONGOPTS=config:,help,skip,delete,exists,allow-duplicates
! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
@ -46,7 +46,7 @@ fi
# read getopts output this way to handle the quoting right:
eval set -- "$PARSED"
exists=n delete=n help=n config="${XDG_CONFIG_HOME:-$HOME/.config}/docspell/ds.conf"
exists=n delete=n help=n config="${XDG_CONFIG_HOME:-$HOME/.config}/docspell/ds.conf" dupes=n
while true; do
case "$1" in
-h|--help)
@ -65,6 +65,10 @@ while true; do
exists=y
shift
;;
--allow-duplicates)
dupes=y
shift
;;
--)
shift
break
@ -93,7 +97,16 @@ checkFile() {
upload_file() {
tf=$($MKTEMP_CMD) rc=0
$CURL_CMD -# -o "$tf" --stderr "$tf" -w "%{http_code}" -XPOST -F file=@"$1" "$2" | (2>&1 1>/dev/null grep 200)
META1=""
META2=""
if [ "$dupes" = "y" ]; then
META1="-F"
META2="meta={\"multiple\": false, \"skipDuplicates\": false}"
else
META1="-F"
META2="meta={\"multiple\": false, \"skipDuplicates\": true}"
fi
$CURL_CMD -# -o "$tf" --stderr "$tf" -w "%{http_code}" -XPOST $META1 "$META2" -F file=@"$1" "$2" | (2>&1 1>/dev/null grep 200)
rc=$(expr $rc + $?)
cat $tf | (2>&1 1>/dev/null grep '{"success":true')
rc=$(expr $rc + $?)
@ -110,6 +123,9 @@ upload_file() {
}
upload() {
if [ "$dupes" == "y" ]; then
upload_file "$1" "$2"
else
checkFile "$2" "$1"
if [ $? -eq 0 ]; then
info "File already exists at url $2"
@ -117,6 +133,7 @@ upload() {
else
upload_file "$1" "$2"
fi
fi
}
showUsage() {
@ -129,6 +146,7 @@ showUsage() {
info " -d | --delete Delete the files when successfully uploaded (value: $delete)"
info " -h | --help Prints this help text. (value: $help)"
info " -e | --exists Checks for the existence of a file instead of uploading (value: $exists)"
info " --allow-duplicates Do not skip existing files in docspell (value: $dupes)"
info ""
info "Arguments:"
info " One or more files to check for existence or upload."