Initial commit: paste-getting only, no upload.

This commit is contained in:
osmarks 2017-09-16 18:30:28 +01:00
commit 49a24c11ed
11 changed files with 290 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.stack-work
pastecan.db*

30
LICENSE Normal file
View File

@ -0,0 +1,30 @@
Copyright Oliver Marks (c) 2017
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Oliver Marks here nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

36
Pastecan.cabal Normal file
View File

@ -0,0 +1,36 @@
name: Pastecan
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/githubuser/servant#readme
license: MIT
author: Oliver Marks
maintainer: osmarks@protonmail.com
copyright: 2017 Oliver Marks
category: Web
build-type: Simple
extra-source-files: README.md
cabal-version: >=1.10
executable pastecan
hs-source-dirs: src
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base >= 4.7 && < 5
, servant
, servant-server
, persistent
, persistent-template
, persistent-sqlite
, wai
, warp
, mtl
, aeson
, containers
, string-conversions
, monad-logger
default-language: Haskell2010
other-modules: Model
, API
, Config
, PasteType

1
README.md Normal file
View File

@ -0,0 +1 @@
# servant

2
Setup.hs Normal file
View File

@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

62
src/API.hs Normal file
View File

@ -0,0 +1,62 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
module API where
import Servant
import Control.Monad.Except
import Database.Persist.Sqlite
import Data.String.Conversions
import Control.Monad.Logger
import Network.Wai.Handler.Warp as Warp
import Model
import Config
type GetPasteAPI =
Capture "username" String :> Capture "pasteName" String :> Get '[JSON] Paste
:<|> "raw" :> Capture "username" String :> Capture "pasteName" String :> Get '[PlainText] String
type API = GetPasteAPI
pasteServer :: ServerT GetPasteAPI App
pasteServer = getPasteData :<|> getPasteRaw
justOrError :: ServantErr -> App (Maybe a) -> App a
justOrError e m =
m >>=
(\w -> case w of
Just x -> return x
Nothing -> throwError e)
justOr404 :: App (Maybe a) -> App a
justOr404 = justOrError err404
getPasteData :: String -> String -> App Paste
getPasteData username name = do
userEntity <- justOr404 $ runDB $ getBy $ Username username
let (Entity uid _) = userEntity
pasteEntity <- justOr404 $ runDB $ selectFirst [PasteParent ==. uid, PasteName ==. name] []
let (Entity _ paste) = pasteEntity
return paste
getPasteRaw :: String -> String -> App String
getPasteRaw u n = pasteContent <$> getPasteData u n
server :: HandlerConfig -> Server API
server cfg = enter (appToServer cfg) pasteServer
proxy :: Proxy API
proxy = Proxy
mkApp :: FilePath -> IO Application
mkApp path = do
pool <- runStderrLoggingT $ createSqlitePool (cs path) 5
runSqlPool doMigrations pool
let cfg = HandlerConfig pool
return $ serve proxy (server cfg)
runApp :: Int -> FilePath -> IO ()
runApp port dbFile =
Warp.run port =<< mkApp dbFile

28
src/Config.hs Normal file
View File

@ -0,0 +1,28 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}
module Config where
import Control.Monad.Reader
import Control.Monad.Except
import Database.Persist
import Database.Persist.Sql
import Servant
data HandlerConfig = HandlerConfig
{ db :: ConnectionPool
}
newtype App a = App
{ runApp :: ReaderT HandlerConfig Handler a
} deriving (Functor, Applicative, Monad, MonadReader HandlerConfig, MonadError ServantErr, MonadIO)
appToServer :: HandlerConfig -> App :~> Handler
appToServer cfg = NT (flip runReaderT cfg . runApp)
runDB :: (MonadReader HandlerConfig m, MonadIO m) => SqlPersistT IO b -> m b
runDB query = do
db <- asks db
liftIO $ runSqlPool query db

9
src/Main.hs Normal file
View File

@ -0,0 +1,9 @@
module Main where
import Network.Wai
import Network.Wai.Handler.Warp
import API
main :: IO ()
main = runApp 3000 "pastecan.db"

37
src/Model.hs Normal file
View File

@ -0,0 +1,37 @@
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
module Model where
import GHC.Generics
import Database.Persist
import Database.Persist.Sql
import Database.Persist.TH
import PasteType
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
User json
username String
Username username
deriving Show Generic
Paste json
parent UserId
name String
content String
type PasteType
deriving Show Generic
|]
doMigrations :: SqlPersistT IO ()
doMigrations = runMigration migrateAll

17
src/PasteType.hs Normal file
View File

@ -0,0 +1,17 @@
-- This module only exists because of the GHC stage restriction.
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
module PasteType where
import Database.Persist.TH
import GHC.Generics
import Data.Aeson
data PasteType = PlainText deriving (Show, Read, Eq, Generic)
instance FromJSON PasteType
instance ToJSON PasteType
derivePersistField "PasteType"

66
stack.yaml Normal file
View File

@ -0,0 +1,66 @@
# This file was automatically generated by 'stack init'
#
# Some commonly used options have been documented as comments in this file.
# For advanced use and comprehensive documentation of the format, please see:
# https://docs.haskellstack.org/en/stable/yaml_configuration/
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
# A snapshot resolver dictates the compiler version and the set of packages
# to be used for project dependencies. For example:
#
# resolver: lts-3.5
# resolver: nightly-2015-09-21
# resolver: ghc-7.10.2
# resolver: ghcjs-0.1.0_ghc-7.10.2
# resolver:
# name: custom-snapshot
# location: "./custom-snapshot.yaml"
resolver: lts-9.3
# User packages to be built.
# Various formats can be used as shown in the example below.
#
# packages:
# - some-directory
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
# - location:
# git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
# extra-dep: true
# subdirs:
# - auto-update
# - wai
#
# A package marked 'extra-dep: true' will only be built if demanded by a
# non-dependency (i.e. a user package), and its test suites and benchmarks
# will not be run. This is useful for tweaking upstream packages.
packages:
- .
# Dependency packages to be pulled from upstream that are not in the resolver
# (e.g., acme-missiles-0.3)
extra-deps: []
# Override default flag values for local packages and extra-deps
flags: {}
# Extra package databases containing global packages
extra-package-dbs: []
# Control whether we use the GHC we find on the path
# system-ghc: true
#
# Require a specific version of stack, using version ranges
# require-stack-version: -any # Default
# require-stack-version: ">=1.5"
#
# Override the architecture used by stack, especially useful on Windows
# arch: i386
# arch: x86_64
#
# Extra directories used by stack for building
# extra-include-dirs: [/path/to/dir]
# extra-lib-dirs: [/path/to/dir]
#
# Allow a newer minor version of GHC than the snapshot specifies
# compiler-check: newer-minor