Compare commits
10 Commits
1011ac907d
...
ae7ba0141e
Author | SHA1 | Date | |
---|---|---|---|
|
ae7ba0141e | ||
|
062a76c8ba | ||
|
e045575dda | ||
|
9cdd10eb0e | ||
|
12099b5e9e | ||
|
72b3e38980 | ||
|
11c4e92cc7 | ||
|
e2f7ebe6de | ||
|
b7e88fcfc9 | ||
|
712008105d |
14
README.md
14
README.md
@ -1,11 +1,15 @@
|
|||||||
# Quotes API
|
# Quotes API
|
||||||
|
|
||||||
Personal, bare bones [readwise] alternative.
|
Personal, bare bones [readwise] alternative.
|
||||||
|
|
||||||
|
<http://quotes.dbalan.in>
|
||||||
|
|
||||||
Have
|
Have
|
||||||
- [ ] Parsers
|
- Parsers
|
||||||
- Read from kindle
|
- [-] Read from kindle
|
||||||
- [ ] Minimal API
|
- [x] Read from readwise
|
||||||
|
- [x] Read from KOReader
|
||||||
|
- [x] Minimal API
|
||||||
- Expose random-quote API
|
- Expose random-quote API
|
||||||
- [ ] Minimal UI
|
- [x] Minimal UI
|
||||||
- Expose a webpage with random and whole quotes
|
- Expose a webpage with random and whole quotes
|
||||||
|
59
app/Main.hs
59
app/Main.hs
@ -11,55 +11,31 @@ import Servant
|
|||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Servant.HTML.Blaze
|
import Servant.HTML.Blaze
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Text.Encoding (decodeUtf8)
|
import Data.Text.Encoding (encodeUtf8)
|
||||||
import Crypto.Argon2
|
import Data.ByteString.Lazy (fromStrict)
|
||||||
import Data.Text.Short (fromText, ShortText)
|
|
||||||
import Data.ByteString (ByteString)
|
|
||||||
|
|
||||||
import Api.Types
|
import Api.Types
|
||||||
import qualified Parsers.KOReader as KO
|
import qualified Parsers.KOReader as KO
|
||||||
|
import qualified Parsers.Readwise as RW
|
||||||
import Config
|
import Config
|
||||||
import Options.Applicative
|
import Options.Applicative
|
||||||
|
import Database
|
||||||
data User = User
|
|
||||||
{ username :: T.Text
|
|
||||||
, password :: ByteString
|
|
||||||
} deriving (Show, Eq)
|
|
||||||
|
|
||||||
type API = Get '[HTML] Quote
|
type API = Get '[HTML] Quote
|
||||||
:<|> "quotes" :> Get '[JSON] [Quote]
|
:<|> "quotes" :> Get '[JSON] [Quote]
|
||||||
:<|> "quote" :> "random" :> Get '[JSON] Quote
|
:<|> "quote" :> "random" :> Get '[JSON] Quote
|
||||||
:<|> "today" :> Get '[HTML] Quote
|
:<|> "today" :> Get '[HTML] Quote
|
||||||
:<|> BasicAuth "update data" User :> ("koreader" :> ReqBody '[JSON] KO.KoHighlight :> Post '[JSON] NoContent)
|
|
||||||
|
|
||||||
api :: Proxy API
|
api :: Proxy API
|
||||||
api = Proxy
|
api = Proxy
|
||||||
|
|
||||||
checkBasicAuth :: T.Text -> ShortText -> BasicAuthCheck User
|
|
||||||
checkBasicAuth user passhash = BasicAuthCheck $ \authData ->
|
|
||||||
let username = decodeUtf8 (basicAuthUsername authData)
|
|
||||||
password = basicAuthPassword authData
|
|
||||||
in
|
|
||||||
case user == username of
|
|
||||||
False -> return NoSuchUser
|
|
||||||
True -> case verifyEncoded passhash password of
|
|
||||||
Argon2Ok -> return $ Authorized $ User username password
|
|
||||||
_ -> return Unauthorized
|
|
||||||
|
|
||||||
|
|
||||||
initDb :: FilePath -> IO ()
|
|
||||||
initDb dbFile = withConnection dbFile $ \conn ->
|
|
||||||
execute_ conn
|
|
||||||
[sql|CREATE TABLE IF NOT EXISTS quotes ( quote text non null
|
|
||||||
, author text
|
|
||||||
, title text
|
|
||||||
, page text
|
|
||||||
, chapter text
|
|
||||||
, created_on integer);|]
|
|
||||||
|
|
||||||
-- | TODO: readerT
|
-- | TODO: readerT
|
||||||
server :: FilePath -> Server API
|
server :: FilePath -> Server API
|
||||||
server dbf = randomQuote dbf :<|> listQuotes dbf :<|> randomQuote dbf :<|> randomQuote dbf :<|> (\_ -> addKoReader dbf)
|
server dbf = randomQuote dbf
|
||||||
|
:<|> listQuotes dbf
|
||||||
|
:<|> randomQuote dbf
|
||||||
|
:<|> randomQuote dbf
|
||||||
|
|
||||||
-- | API begins here
|
-- | API begins here
|
||||||
randomQuote :: FilePath -> Handler Quote
|
randomQuote :: FilePath -> Handler Quote
|
||||||
@ -76,17 +52,18 @@ listQuotes db = liftIO $ withConnection db $ \conn -> query_ conn [sql|SELECT *
|
|||||||
|
|
||||||
addKoReader :: FilePath -> KO.KoHighlight -> Handler NoContent
|
addKoReader :: FilePath -> KO.KoHighlight -> Handler NoContent
|
||||||
addKoReader db hl = do
|
addKoReader db hl = do
|
||||||
liftIO $ withConnection db $ \c ->
|
liftIO $ insertQts db (KO.parse hl)
|
||||||
executeMany c qry qts
|
pure NoContent
|
||||||
|
|
||||||
|
addReadwise :: FilePath -> T.Text -> Handler NoContent
|
||||||
|
addReadwise db hl = do
|
||||||
|
let
|
||||||
|
qts = RW.parse (fromStrict $ encodeUtf8 hl)
|
||||||
|
liftIO $ print $ show qts
|
||||||
pure NoContent
|
pure NoContent
|
||||||
where
|
|
||||||
qry = [sql|INSERT INTO quotes VALUES (?,?,?,?,?,?);|]
|
|
||||||
qts = KO.parse hl
|
|
||||||
|
|
||||||
runApp :: AppConfig -> IO ()
|
runApp :: AppConfig -> IO ()
|
||||||
runApp c = run (appPort c) (serveWithContext api ctx $ server (appDbFile c))
|
runApp c = run (appPort c) (serve api $ server (appDbFile c))
|
||||||
where
|
|
||||||
ctx = checkBasicAuth (appUser c) (fromText $ appPassHash c):. EmptyContext
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
60
flake.lock
Normal file
60
flake.lock
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1694529238,
|
||||||
|
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1699562885,
|
||||||
|
"narHash": "sha256-fb7RDv0ePGzayhGvkBh9NrilU3pCecgfbbTNPHprRfg=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "97b0ae26f7c8a1682b5437a64edcd73ab1798c9b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
90
flake.nix
Normal file
90
flake.nix
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2021 Serokell <https://serokell.io/>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
{
|
||||||
|
description = "quotes-api";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
haskellPackages = pkgs.haskellPackages;
|
||||||
|
|
||||||
|
jailbreakUnbreak = pkg:
|
||||||
|
pkgs.haskell.lib.doJailbreak (pkg.overrideAttrs (_: { meta = { }; }));
|
||||||
|
|
||||||
|
# DON'T FORGET TO PUT YOUR PACKAGE NAME HERE, REMOVING `throw`
|
||||||
|
packageName = "quotes-api";
|
||||||
|
in {
|
||||||
|
packages.${packageName} = haskellPackages.callCabal2nix packageName self
|
||||||
|
rec {
|
||||||
|
# Dependency overrides go here
|
||||||
|
};
|
||||||
|
|
||||||
|
packages.default = self.packages.${system}.${packageName};
|
||||||
|
defaultPackage = self.packages.${system}.default;
|
||||||
|
|
||||||
|
nixosModules = {
|
||||||
|
quotes-api = { config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let cfg = config.services.quotes-api;
|
||||||
|
in {
|
||||||
|
options.services.quotes-api = {
|
||||||
|
enable = mkEnableOption "Enables quotes api service";
|
||||||
|
|
||||||
|
port = mkOption rec {
|
||||||
|
type = types.int;
|
||||||
|
default = 8123;
|
||||||
|
example = default;
|
||||||
|
description = "bind port";
|
||||||
|
};
|
||||||
|
|
||||||
|
dbpath = mkOption rec {
|
||||||
|
type = types.string;
|
||||||
|
default = "/tmp/sqlite.db";
|
||||||
|
example = default;
|
||||||
|
description = "Path to sqlite database";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
systemd.services."quotes-api" = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
|
serviceConfig =
|
||||||
|
let pkg = self.packages.${pkgs.system}.default;
|
||||||
|
in {
|
||||||
|
Restart = "on-failure";
|
||||||
|
ExecStart = "${pkg}/bin/quotes-api --port ${
|
||||||
|
builtins.toString cfg.port
|
||||||
|
} --dbpath ${cfg.dbpath}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nixosModule = self.nixosModules.${system}.quotes-api;
|
||||||
|
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
haskellPackages.haskell-language-server # you must build it with your ghc to work
|
||||||
|
ghcid
|
||||||
|
hlint
|
||||||
|
ghc
|
||||||
|
cabal-install
|
||||||
|
];
|
||||||
|
inputsFrom =
|
||||||
|
map (__getAttr "env") (__attrValues self.packages.${system});
|
||||||
|
};
|
||||||
|
devShell = self.devShells.${system}.default;
|
||||||
|
});
|
||||||
|
}
|
21
importer/Main.hs
Normal file
21
importer/Main.hs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import Options.Applicative
|
||||||
|
import qualified Data.ByteString.Lazy as BSL
|
||||||
|
|
||||||
|
import Config
|
||||||
|
import Database
|
||||||
|
|
||||||
|
import qualified Parsers.Readwise as RW
|
||||||
|
|
||||||
|
runImporter :: FilePath -> FilePath -> IO ()
|
||||||
|
runImporter db rw = do
|
||||||
|
x <- BSL.readFile rw
|
||||||
|
let y = RW.parse x
|
||||||
|
case y of
|
||||||
|
Left err -> print err
|
||||||
|
Right qts -> insertQts db qts
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
conf <- execParser importerParserOpts
|
||||||
|
initDb (ioAppDbFile conf)
|
||||||
|
runImporter (ioAppDbFile conf) (ioReadwiseFile conf)
|
61
lib/Config.hs
Normal file
61
lib/Config.hs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
module Config
|
||||||
|
( parserOpts
|
||||||
|
, AppConfig(..)
|
||||||
|
, importerParserOpts
|
||||||
|
, ImporterConfig(..)
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Options.Applicative
|
||||||
|
|
||||||
|
data AppConfig = AppConfig
|
||||||
|
{ appPort :: Int
|
||||||
|
, appDbFile :: FilePath
|
||||||
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
|
appConfig :: Parser AppConfig
|
||||||
|
appConfig = AppConfig
|
||||||
|
<$> option auto
|
||||||
|
( long "port"
|
||||||
|
<> help "port to listen"
|
||||||
|
<> showDefault
|
||||||
|
<> value 8000
|
||||||
|
<> metavar "INT")
|
||||||
|
<*> strOption
|
||||||
|
( long "dbpath"
|
||||||
|
<> help "sqlite db file path"
|
||||||
|
<> showDefault
|
||||||
|
<> value "quotes.db"
|
||||||
|
<> metavar "TARGET")
|
||||||
|
|
||||||
|
parserOpts :: ParserInfo AppConfig
|
||||||
|
parserOpts = info (appConfig <**> helper)
|
||||||
|
( fullDesc
|
||||||
|
<> progDesc "Serve Quotes API"
|
||||||
|
<> header "quotes api" )
|
||||||
|
|
||||||
|
data ImporterConfig = ImporterConfig
|
||||||
|
{ ioAppDbFile :: FilePath
|
||||||
|
, ioReadwiseFile :: FilePath
|
||||||
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
|
importerConfig :: Parser ImporterConfig
|
||||||
|
importerConfig = ImporterConfig
|
||||||
|
<$> strOption
|
||||||
|
( long "dbpath"
|
||||||
|
<> help "sqlite db file path"
|
||||||
|
<> showDefault
|
||||||
|
<> value "quotes.db"
|
||||||
|
<> metavar "TARGET")
|
||||||
|
<*> strOption
|
||||||
|
( long "readwise"
|
||||||
|
<> help "readwise export file path"
|
||||||
|
<> showDefault
|
||||||
|
<> value "readwise.csv"
|
||||||
|
<> metavar "RWCSV")
|
||||||
|
|
||||||
|
importerParserOpts :: ParserInfo ImporterConfig
|
||||||
|
importerParserOpts = info (importerConfig <**> helper)
|
||||||
|
( fullDesc
|
||||||
|
<> progDesc "Import data into db"
|
||||||
|
<> header "importer API")
|
25
lib/Database.hs
Normal file
25
lib/Database.hs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
|
||||||
|
module Database where
|
||||||
|
|
||||||
|
import Database.SQLite.Simple.QQ
|
||||||
|
import Database.SQLite.Simple
|
||||||
|
|
||||||
|
import Api.Types
|
||||||
|
|
||||||
|
initDb :: FilePath -> IO ()
|
||||||
|
initDb dbFile = withConnection dbFile $ \conn ->
|
||||||
|
execute_ conn
|
||||||
|
[sql|CREATE TABLE IF NOT EXISTS quotes ( quote text non null
|
||||||
|
, author text
|
||||||
|
, title text
|
||||||
|
, page text
|
||||||
|
, chapter text
|
||||||
|
, created_on integer);|]
|
||||||
|
|
||||||
|
insertQts :: FilePath -> [Quote] -> IO ()
|
||||||
|
insertQts db qts = do
|
||||||
|
withConnection db $ \c ->
|
||||||
|
executeMany c qry qts
|
||||||
|
where
|
||||||
|
qry = [sql|INSERT INTO quotes VALUES (?,?,?,?,?,?);|]
|
51
lib/Parsers/Readwise.hs
Normal file
51
lib/Parsers/Readwise.hs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
module Parsers.Readwise where
|
||||||
|
|
||||||
|
import Data.Csv
|
||||||
|
import Data.Text
|
||||||
|
import Data.Vector (toList)
|
||||||
|
import Data.ByteString.Lazy (ByteString)
|
||||||
|
import Api.Types (Quote(..))
|
||||||
|
|
||||||
|
data RwHighlight = RwHighlight { rhHightlight :: Text
|
||||||
|
, rhTitle :: Text
|
||||||
|
, rhAuthor :: Text
|
||||||
|
, rhBookID :: Text
|
||||||
|
, rhNote :: Text
|
||||||
|
, rhColor :: Text
|
||||||
|
, rhTags :: Text
|
||||||
|
, rhLocationType :: Text
|
||||||
|
, rhLocation :: Text
|
||||||
|
, rhHighlighedAt :: Text
|
||||||
|
, rhDocumentTags :: Text
|
||||||
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance FromNamedRecord RwHighlight where
|
||||||
|
parseNamedRecord m = RwHighlight <$> m .: "Highlight"
|
||||||
|
<*> m .: "Book Title"
|
||||||
|
<*> m .: "Book Author"
|
||||||
|
<*> m .: "Amazon Book ID"
|
||||||
|
<*> m .: "Note"
|
||||||
|
<*> m .: "Color"
|
||||||
|
<*> m .: "Tags"
|
||||||
|
<*> m .: "Location Type"
|
||||||
|
<*> m .: "Location"
|
||||||
|
<*> m .: "Highlighted at"
|
||||||
|
<*> m .: "Document tags"
|
||||||
|
|
||||||
|
parseDocument :: ByteString -> Either String [RwHighlight]
|
||||||
|
parseDocument d = case decodeByName d of
|
||||||
|
Left err -> Left err
|
||||||
|
Right (_, va) -> Right $ toList va
|
||||||
|
|
||||||
|
parse :: ByteString -> Either String [Quote]
|
||||||
|
parse d = case parseDocument d of
|
||||||
|
Left err -> Left err
|
||||||
|
Right rw -> Right $ fmap (\r -> Quote { qQuote = rhHightlight r
|
||||||
|
, qAuthor = rhAuthor r
|
||||||
|
, qTitle = rhTitle r
|
||||||
|
, qPage = rhLocation r
|
||||||
|
, qChapter = Nothing
|
||||||
|
, qCreatedOn = Nothing
|
||||||
|
}) rw
|
@ -61,7 +61,9 @@ library
|
|||||||
-- Modules exported by the library.
|
-- Modules exported by the library.
|
||||||
exposed-modules: Api.Types,
|
exposed-modules: Api.Types,
|
||||||
Parsers.KOReader,
|
Parsers.KOReader,
|
||||||
|
Parsers.Readwise,
|
||||||
Config,
|
Config,
|
||||||
|
Database,
|
||||||
-- Modules included in this library but not exported.
|
-- Modules included in this library but not exported.
|
||||||
-- other-modules:
|
-- other-modules:
|
||||||
|
|
||||||
@ -69,7 +71,7 @@ library
|
|||||||
-- other-extensions:
|
-- other-extensions:
|
||||||
|
|
||||||
-- Other library packages from which modules are imported.
|
-- Other library packages from which modules are imported.
|
||||||
build-depends: base ^>=4.16.3.0,
|
build-depends: base,
|
||||||
text,
|
text,
|
||||||
aeson,
|
aeson,
|
||||||
deriving-aeson,
|
deriving-aeson,
|
||||||
@ -79,6 +81,8 @@ library
|
|||||||
blaze-markup,
|
blaze-markup,
|
||||||
blaze-html,
|
blaze-html,
|
||||||
optparse-applicative,
|
optparse-applicative,
|
||||||
|
cassava,
|
||||||
|
vector,
|
||||||
-- Directories containing source files.
|
-- Directories containing source files.
|
||||||
hs-source-dirs: lib
|
hs-source-dirs: lib
|
||||||
|
|
||||||
@ -100,10 +104,10 @@ executable quotes-api
|
|||||||
|
|
||||||
-- Other library packages from which modules are imported.
|
-- Other library packages from which modules are imported.
|
||||||
build-depends:
|
build-depends:
|
||||||
base ^>=4.16.3.0,
|
base,
|
||||||
sqlite-simple ^>=0.4.18.0,
|
sqlite-simple,
|
||||||
text ^>=1.2.5.0,
|
text,
|
||||||
servant-server ^>=0.19.1,
|
servant-server,
|
||||||
wai,
|
wai,
|
||||||
warp,
|
warp,
|
||||||
aeson,
|
aeson,
|
||||||
@ -111,15 +115,52 @@ executable quotes-api
|
|||||||
quotes-api,
|
quotes-api,
|
||||||
servant-blaze,
|
servant-blaze,
|
||||||
optparse-applicative,
|
optparse-applicative,
|
||||||
argon2,
|
|
||||||
text-short,
|
text-short,
|
||||||
bytestring,
|
bytestring,
|
||||||
|
QuickCheck,
|
||||||
|
|
||||||
-- Directories containing source files.
|
-- Directories containing source files.
|
||||||
hs-source-dirs: app
|
hs-source-dirs: app
|
||||||
|
|
||||||
-- Base language which the package is written in.
|
-- Base language which the package is written in.
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
|
||||||
|
executable quotes-importer
|
||||||
|
-- Import common warning flags.
|
||||||
|
import: warnings
|
||||||
|
|
||||||
|
-- .hs or .lhs file containing the Main module.
|
||||||
|
main-is: Main.hs
|
||||||
|
|
||||||
|
-- Modules included in this executable, other than Main.
|
||||||
|
-- other-modules:
|
||||||
|
|
||||||
|
-- LANGUAGE extensions used by modules in this package.
|
||||||
|
-- other-extensions:
|
||||||
|
|
||||||
|
-- Other library packages from which modules are imported.
|
||||||
|
build-depends:
|
||||||
|
base,
|
||||||
|
sqlite-simple,
|
||||||
|
text,
|
||||||
|
servant-server,
|
||||||
|
wai,
|
||||||
|
warp,
|
||||||
|
aeson,
|
||||||
|
deriving-aeson,
|
||||||
|
quotes-api,
|
||||||
|
servant-blaze,
|
||||||
|
optparse-applicative,
|
||||||
|
text-short,
|
||||||
|
bytestring,
|
||||||
|
QuickCheck,
|
||||||
|
-- Directories containing source files.
|
||||||
|
hs-source-dirs: importer
|
||||||
|
|
||||||
|
-- Base language which the package is written in.
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
test-suite quotes-api-test
|
test-suite quotes-api-test
|
||||||
-- Import common warning flags.
|
-- Import common warning flags.
|
||||||
import: warnings
|
import: warnings
|
||||||
@ -144,5 +185,5 @@ test-suite quotes-api-test
|
|||||||
|
|
||||||
-- Test dependencies.
|
-- Test dependencies.
|
||||||
build-depends:
|
build-depends:
|
||||||
base ^>=4.16.3.0,
|
base,
|
||||||
quotes-api
|
quotes-api
|
||||||
|
16
shell.nix
16
shell.nix
@ -1,16 +0,0 @@
|
|||||||
let
|
|
||||||
pkgs = import <unstable> { }; # pin the channel to ensure reproducibility!
|
|
||||||
in
|
|
||||||
pkgs.haskellPackages.developPackage {
|
|
||||||
root = ./.;
|
|
||||||
modifier = drv:
|
|
||||||
pkgs.haskell.lib.addBuildTools drv (with pkgs.haskellPackages;
|
|
||||||
[ cabal-install
|
|
||||||
ghcid
|
|
||||||
ghc
|
|
||||||
haskell-language-server
|
|
||||||
zlib
|
|
||||||
cabal-plan
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user