├── .dir-locals.el ├── .gitignore ├── LICENSE ├── README.md ├── app ├── DevelMain.hs ├── devel.hs └── main.hs ├── config ├── favicon.ico ├── keter.yml ├── models.persistentmodels ├── robots.txt ├── routes.yesodroutes ├── settings.yml └── test-settings.yml ├── messages └── en.msg ├── package.yaml ├── src ├── Application.hs ├── Foundation.hs ├── Handler │ ├── Account.hs │ ├── Categories.hs │ ├── Comments.hs │ ├── Common.hs │ ├── Download.hs │ ├── EditCategory.hs │ ├── EditComment.hs │ ├── EditEntry.hs │ ├── EditEntrySubscription.hs │ ├── EditFeedback.hs │ ├── EditHelp.hs │ ├── EditPage.hs │ ├── EditUserAbout.hs │ ├── EditUserEntry.hs │ ├── EditUserPage(Deprecated).hs │ ├── EditUserSubscription.hs │ ├── EmailSetting.hs │ ├── Entries.hs │ ├── Feedback.hs │ ├── File.hs │ ├── Files.hs │ ├── Home.hs │ ├── LoginSetting.hs │ ├── MaintainEntry.hs │ ├── Maintenance.hs │ ├── NewCategory.hs │ ├── NewEntrySubscription.hs │ ├── NewUserSubscription.hs │ ├── Page.hs │ ├── Pages.hs │ ├── Parse.hs │ ├── Settings.hs │ ├── Slug.hs │ ├── Subscriptions.hs │ ├── Tool.hs │ ├── Tree.hs │ ├── UserEntries.hs │ ├── UserEntry.hs │ ├── UserHome.hs │ ├── Users.hs │ └── Vote.hs ├── Import.hs ├── Import │ └── NoFoundation.hs ├── Model.hs ├── Parse │ ├── KillOldProcesses.hs │ ├── Parser.hs │ └── lean.xml ├── Settings.hs ├── Settings │ └── StaticFiles.hs └── Yesod │ └── Auth │ ├── Extra.hs │ └── OAuth2 │ └── ORCID.hs ├── stack.yaml ├── stack.yaml.lock ├── static ├── css │ ├── bootstrap-theme.css │ └── bootstrap.min.css ├── editor │ ├── LICENSE │ ├── css │ │ ├── ace.css │ │ ├── github-1.png │ │ ├── github-2.png │ │ ├── github_dark-1.png │ │ ├── github_dark-2.png │ │ ├── github_light_default-1.png │ │ ├── github_light_default-2.png │ │ ├── main-1.png │ │ ├── main-10.png │ │ ├── main-11.png │ │ ├── main-12.png │ │ ├── main-13.png │ │ ├── main-14.png │ │ ├── main-15.png │ │ ├── main-16.png │ │ ├── main-17.png │ │ ├── main-18.png │ │ ├── main-19.png │ │ ├── main-2.png │ │ ├── main-20.png │ │ ├── main-21.png │ │ ├── main-22.png │ │ ├── main-22.svg │ │ ├── main-23.png │ │ ├── main-3.png │ │ ├── main-4.png │ │ ├── main-5.png │ │ ├── main-5.svg │ │ ├── main-6.png │ │ ├── main-6.svg │ │ ├── main-7.png │ │ ├── main-7.svg │ │ ├── main-8.png │ │ ├── main-8.svg │ │ ├── main-9.png │ │ ├── main-9.svg │ │ ├── textmate-1.png │ │ ├── textmate-2.png │ │ └── theme │ │ │ ├── github.css │ │ │ ├── github_light_default.css │ │ │ └── textmate.css │ └── src-min │ │ ├── ace.js │ │ ├── ext-beautify.js │ │ ├── ext-code_lens.js │ │ ├── ext-command_bar.js │ │ ├── ext-elastic_tabstops_lite.js │ │ ├── ext-emmet.js │ │ ├── ext-error_marker.js │ │ ├── ext-hardwrap.js │ │ ├── ext-inline_autocomplete.js │ │ ├── ext-keybinding_menu.js │ │ ├── ext-language_tools.js │ │ ├── ext-linking.js │ │ ├── ext-modelist.js │ │ ├── ext-options.js │ │ ├── ext-prompt.js │ │ ├── ext-rtl.js │ │ ├── ext-searchbox.js │ │ ├── ext-settings_menu.js │ │ ├── ext-simple_tokenizer.js │ │ ├── ext-spellcheck.js │ │ ├── ext-split.js │ │ ├── ext-static_highlight.js │ │ ├── ext-statusbar.js │ │ ├── ext-textarea.js │ │ ├── ext-themelist.js │ │ ├── ext-whitespace.js │ │ ├── keybinding-emacs.js │ │ ├── keybinding-sublime.js │ │ ├── keybinding-vim.js │ │ ├── keybinding-vscode.js │ │ ├── mode-html.js │ │ ├── mode-latex.js │ │ ├── mode-markdown.js │ │ ├── mode-tex.js │ │ └── snippets │ │ ├── html.js │ │ ├── latex.js │ │ ├── markdown.js │ │ └── tex.js ├── icons │ ├── default-avatar.svg │ ├── envelope.svg │ ├── google-logo.svg │ ├── mathstodon-logo.svg │ ├── orcid-logo.svg │ ├── qr-code.svg │ ├── reddit-logo.svg │ └── twitter-logo.svg └── js │ ├── bootstrap.min.js │ ├── bootstrap.theme.js │ ├── jquery.min.js │ ├── js.cookie.min.js │ └── qrcode.min.js ├── templates ├── default-layout-wrapper.hamlet ├── default-layout.hamlet ├── default-layout.lucius ├── editor-md.julius ├── editor-tex.julius ├── editor.julius ├── homepage.hamlet ├── homepage.julius └── homepage.lucius └── test ├── Handler ├── AccountSpec.hs ├── CategoriesSpec.hs ├── CommentSpec.hs ├── CommonSpec.hs ├── DownloadSpec.hs ├── EditCategorySpec.hs ├── EditEntrySpec.hs ├── EditFeedbackSpec.hs ├── EditHelpSpec.hs ├── EditUserAboutSpec.hs ├── Entries0Spec.hs ├── EntrySubscriptionSpec.hs ├── FeedbackSpec.hs ├── HomeSpec.hs ├── MaintainEntrySpec.hs ├── MaintenanceSpec.hs ├── NewCategorySpec.hs ├── NewEntrySubscriptionSpec.hs ├── NewUserSubscriptionSpec.hs ├── Pages0Spec.hs ├── ProfileSpec.hs ├── RedirectSpec.hs ├── SlugSpec.hs ├── SubscriptionSpec.hs ├── ToolSpec.hs ├── TreeSpec.hs ├── UserSubscriptionSpec.hs └── VoteSpec.hs ├── Spec.hs └── TestImport.hs /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((haskell-mode . ((haskell-indent-spaces . 4) 2 | (haskell-process-use-ghci . t))) 3 | (hamlet-mode . ((hamlet/basic-offset . 4) 4 | (haskell-process-use-ghci . t)))) 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist* 2 | static/tmp/ 3 | static/files/ 4 | static/combined/ 5 | config/client_session_key.aes 6 | *.hi 7 | *.o 8 | *.sqlite3 9 | *.sqlite3-shm 10 | *.sqlite3-wal 11 | .hsenv* 12 | cabal-dev/ 13 | .stack-work/ 14 | .stack-work-devel/ 15 | yesod-devel/ 16 | .cabal-sandbox 17 | cabal.sandbox.config 18 | .DS_Store 19 | *.swp 20 | *.keter 21 | *~ 22 | \#* 23 | functor-network.cabal 24 | cache/ 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2025 Chun Ding 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## About the project 2 | 3 | This is the source code for the [Functor Network](https://functor.network) - a blog platform for mathematicians. The term "mathematician" here is used in a broad sense, encompassing people studying math at any level, as well as professionals in related fields. While we provide special support for mathematicians, anyone can register a blog site on our platform and express themselves on a variety of topics, whether they're related to math or not. 4 | 5 | ## Features 6 | 7 | 8 | In a word, every feature on our platform is thoughtfully designed for mathematicians. 9 | 10 | - **Effortless Typesetting.** Typesetting math on the web can be exhausting and time-consuming. On our platform, you focus on the content—we’ll take care of the typesetting. 11 | 12 | - **Powered by a Real TeX Engine.** We might be the only blogging platform that renders mathematical content using a full TeX Live system. Enjoy complete LaTeX compatibility—import packages, use math environments, or even paste existing LaTeX documents directly. 13 | 14 | - **Flexible Writing Formats.** Write in *Pure LaTeX* or *Markdown with LaTeX*—your choice. Either way, you retain powerful features like cross-referencing, bibliographies, and theorem environments. 15 | 16 | - **PDF Export.** Need an offline copy? Download any post as a beautifully typeset PDF with one click. 17 | 18 | - **Minimalist & Focused.** No clutter. No distractions. Just a clean, efficient, and secure space for your mathematical thoughts. 19 | 20 | Other small yet useful features include syntax highlighting for Lean and integration with social platforms popular among mathematicians. 21 | 22 | 23 | ## Comparison 24 | 25 | We make a comparison with other blog platform to clarify our features: 26 | 27 | | Feature | Our Platform | Other Platforms | 28 | |----------------------------------|------------------------------------------------------------|------------------------------------------------------------| 29 | | Write posts directly in LaTeX | Supported | Not supported | 30 | | Math formula rendering | Built-in support | Not supported or requires add-ons | 31 | | Preserve LaTeX code | Yes | May corrupt backslashes or encode symbols like `<`, `&`, etc. | 32 | | LaTeX packages | Supported — different packages can be used per post | Not supported | 33 | | Automated numbering and referencing | Supported | Not supported or only partially supported | 34 | | Custom LaTeX commands | Supported | Possibly supported | 35 | | Theorem-like environments | Supported | Not supported | 36 | | Bibliography | Supported | Possibly supported | 37 | | Markdown with math features | Supported | Possibly supported but limited | 38 | | PDF export | Supported | Not supported | 39 | | Syntax highlight for Lean | Supported | Possibly supported | 40 | | Design philosophy | Clean and minimal — intentionally abstract | Often cluttered with unnecessary features | 41 | | Editor | Plain text editor with live preview — focuses on content | WYSIWYG editor — may be problematic for math content | 42 | 43 | 44 | ## Credits 45 | 46 | **Functor Network** is developed by [Chun Ding](https://github.com/c-ding-math), © 2023-2025 Chun Ding, licensed under the [MIT License](https://opensource.org/licenses/MIT). 47 | It is built on the [Yesod](https://www.yesodweb.com/) web framework, © 2012–2017 Michael Snoyman, also under the [MIT License](https://opensource.org/licenses/MIT). 48 | 49 | This project includes the following third-party resources: 50 | 51 | - `static/js/jquery.min.js` — [jQuery](https://jquery.com/), © 2005–2025 jQuery Foundation, [MIT License](https://opensource.org/licenses/MIT) 52 | - `static/css/bootstrap.min.css` and `static/js/bootstrap.min.js` — [Bootstrap](https://getbootstrap.com/), © 2011–2025 Twitter, Inc., [MIT License](https://opensource.org/licenses/MIT) 53 | - SVG icons from [Bootstrap](https://getbootstrap.com/), © 2011–2025 Twitter, Inc., [MIT License](https://opensource.org/licenses/MIT) 54 | - Syntax definition for Lean language highlighting — © 2025 [Hagb (Junyu Guo)](https://github.com/Hagb), [MIT License](https://opensource.org/licenses/MIT) 55 | - `static/editor` — [Ace Editor](https://ace.c9.io/), © 2010 Ajax.org B.V., [License](static/editor/LICENSE) 56 | - `static/js/js.cookie.min.js` - [js-cookie](https://github.com/js-cookie/js-cookie), © 2018 Klaus Hartl, Fagner Brack, GitHub Contributors, [MIT License](https://opensource.org/licenses/MIT) 57 | - `static/js/qrcode.min.js` - [QRCode.js](https://github.com/davidshimjs/qrcodejs), © 2012 davidshimjs, [MIT License](https://opensource.org/licenses/MIT) 58 | -------------------------------------------------------------------------------- /app/DevelMain.hs: -------------------------------------------------------------------------------- 1 | -- | Running your app inside GHCi. 2 | -- 3 | -- This option provides significantly faster code reload compared to 4 | -- @yesod devel@. However, you do not get automatic code reload 5 | -- (which may be a benefit, depending on your perspective). To use this: 6 | -- 7 | -- 1. Start up GHCi 8 | -- 9 | -- $ stack ghci functor-network:lib --no-load --work-dir .stack-work-devel 10 | -- 11 | -- 2. Load this module 12 | -- 13 | -- > :l app/DevelMain.hs 14 | -- 15 | -- 3. Run @update@ 16 | -- 17 | -- > DevelMain.update 18 | -- 19 | -- 4. Your app should now be running, you can connect at http://localhost:3000 20 | -- 21 | -- 5. Make changes to your code 22 | -- 23 | -- 6. After saving your changes, reload by running: 24 | -- 25 | -- > :r 26 | -- > DevelMain.update 27 | -- 28 | -- You can also call @DevelMain.shutdown@ to stop the app 29 | -- 30 | -- There is more information about this approach, 31 | -- on the wiki: https://github.com/yesodweb/yesod/wiki/ghci 32 | -- 33 | -- WARNING: GHCi does not notice changes made to your template files. 34 | -- If you change a template, you'll need to either exit GHCi and reload, 35 | -- or manually @touch@ another Haskell module. 36 | 37 | module DevelMain where 38 | 39 | import Prelude 40 | import Application (getApplicationRepl, shutdownApp) 41 | 42 | import Control.Monad ((>=>)) 43 | import Control.Concurrent 44 | import Data.IORef 45 | import Foreign.Store 46 | import Network.Wai.Handler.Warp 47 | import GHC.Word 48 | 49 | -- | Start or restart the server. 50 | -- newStore is from foreign-store. 51 | -- A Store holds onto some data across ghci reloads 52 | update :: IO () 53 | update = do 54 | mtidStore <- lookupStore tidStoreNum 55 | case mtidStore of 56 | -- no server running 57 | Nothing -> do 58 | done <- storeAction doneStore newEmptyMVar 59 | tid <- start done 60 | _ <- storeAction (Store tidStoreNum) (newIORef tid) 61 | return () 62 | -- server is already running 63 | Just tidStore -> restartAppInNewThread tidStore 64 | where 65 | doneStore :: Store (MVar ()) 66 | doneStore = Store 0 67 | 68 | -- shut the server down with killThread and wait for the done signal 69 | restartAppInNewThread :: Store (IORef ThreadId) -> IO () 70 | restartAppInNewThread tidStore = modifyStoredIORef tidStore $ \tid -> do 71 | killThread tid 72 | withStore doneStore takeMVar 73 | readStore doneStore >>= start 74 | 75 | 76 | -- | Start the server in a separate thread. 77 | start :: MVar () -- ^ Written to when the thread is killed. 78 | -> IO ThreadId 79 | start done = do 80 | (port, site, app) <- getApplicationRepl 81 | forkFinally 82 | (runSettings (setPort port defaultSettings) app) 83 | -- Note that this implies concurrency 84 | -- between shutdownApp and the next app that is starting. 85 | -- Normally this should be fine 86 | (\_ -> putMVar done () >> shutdownApp site) 87 | 88 | -- | kill the server 89 | shutdown :: IO () 90 | shutdown = do 91 | mtidStore <- lookupStore tidStoreNum 92 | case mtidStore of 93 | -- no server running 94 | Nothing -> putStrLn "no Yesod app running" 95 | Just tidStore -> do 96 | withStore tidStore $ readIORef >=> killThread 97 | putStrLn "Yesod app is shutdown" 98 | 99 | tidStoreNum :: Word32 100 | tidStoreNum = 1 101 | 102 | modifyStoredIORef :: Store (IORef a) -> (a -> IO a) -> IO () 103 | modifyStoredIORef store f = withStore store $ \ref -> do 104 | v <- readIORef ref 105 | f v >>= writeIORef ref 106 | -------------------------------------------------------------------------------- /app/devel.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE PackageImports #-} 2 | import "functor-network" Application (develMain) 3 | import Prelude (IO) 4 | 5 | main :: IO () 6 | main = develMain 7 | -------------------------------------------------------------------------------- /app/main.hs: -------------------------------------------------------------------------------- 1 | import Prelude (IO) 2 | import Application (appMain) 3 | 4 | main :: IO () 5 | main = appMain 6 | -------------------------------------------------------------------------------- /config/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/c-ding-math/functor-network/7e7a7d8770c191f4ae74a0592908495377baeb74/config/favicon.ico -------------------------------------------------------------------------------- /config/keter.yml: -------------------------------------------------------------------------------- 1 | # After you've edited this file, remove the following line to allow 2 | # `yesod keter` to build your bundle. 3 | # 4 | # Also, please make sure that `port` value on `config/settings.yaml` is set to 5 | # use `PORT` env variable. 6 | #user-edited: false 7 | 8 | # A Keter app is composed of 1 or more stanzas. The main stanza will define our 9 | # web application. See the Keter documentation for more information on 10 | # available stanzas. 11 | stanzas: 12 | 13 | # Your Yesod application. 14 | - type: webapp 15 | 16 | # Name of your executable. You are unlikely to need to change this. 17 | # Note that all file paths are relative to the keter.yml file. 18 | # 19 | # The path given is for Stack projects. If you're still using cabal, change 20 | # to 21 | # exec: ../dist/build/functor-network/functor-network 22 | exec: ../dist/bin/functor-network 23 | 24 | # Command line options passed to your application. 25 | args: [] 26 | 27 | hosts: 28 | # You can specify one or more hostnames for your application to respond 29 | # to. The primary hostname will be used for generating your application 30 | # root. 31 | - functor.network 32 | 33 | # Enable to force Keter to redirect to https 34 | # Can be added to any stanza 35 | requires-secure: true 36 | 37 | # Static files. 38 | - type: static-files 39 | hosts: 40 | - static.functor.network 41 | root: ../static 42 | 43 | # Uncomment to turn on directory listings. 44 | # directory-listing: true 45 | 46 | # Redirect www to non-www domain 47 | - type: redirect 48 | 49 | hosts: 50 | - www.functor.network 51 | actions: 52 | - host: functor.network 53 | secure: true 54 | # secure: false 55 | # port: 80 56 | 57 | # Uncomment to switch to a non-permanent redirect. 58 | # status: 303 59 | 60 | # Use the following to automatically copy your bundle upon creation via `yesod 61 | # keter`. Uses `scp` internally, so you can set it to a remote destination 62 | # copy-to: user@host:/opt/keter/incoming/ 63 | 64 | # You can pass arguments to `scp` used above. This example limits bandwidth to 65 | # 1024 Kbit/s and uses port 2222 instead of the default 22 66 | # copy-to-args: 67 | # - "-l 1024" 68 | # - "-P 2222" 69 | 70 | # If you would like to have Keter automatically create a PostgreSQL database 71 | # and set appropriate environment variables for it to be discovered, uncomment 72 | # the following line. 73 | # plugins: 74 | # postgres: true 75 | -------------------------------------------------------------------------------- /config/models.persistentmodels: -------------------------------------------------------------------------------- 1 | -- By default this file is used by `persistFileWith` in Model.hs (which is imported by Foundation.hs) 2 | -- Syntax for this file here: https://github.com/yesodweb/persistent/blob/master/docs/Persistent-entity-syntax.md 3 | Vote 4 | userId UserId OnDeleteCascade 5 | entryId EntryId OnDeleteCascade 6 | inserted UTCTime default=CURRENT_TIME 7 | UniqueVote userId entryId 8 | deriving Show 9 | 10 | EntryTree 11 | node EntryId OnDeleteCascade 12 | parent EntryId OnDeleteCascade 13 | inserted UTCTime default=CURRENT_TIME 14 | UniqueEntryTree node parent 15 | 16 | UserSubscription 17 | email Text 18 | userId UserId OnDeleteCascade 19 | inserted UTCTime 20 | key Text Maybe 21 | verified Bool 22 | client String Maybe 23 | UniqueUserSubscription email userId 24 | deriving Show 25 | 26 | EntrySubscription 27 | email Text 28 | entryId EntryId OnDeleteCascade 29 | inserted UTCTime 30 | key Text Maybe 31 | verified Bool 32 | client String Maybe 33 | UniqueEntrySubscription email entryId 34 | deriving Show 35 | 36 | Entry 37 | userId UserId OnDeleteCascade 38 | inserted UTCTime default=CURRENT_TIME 39 | updated UTCTime default=CURRENT_TIME 40 | type EntryType 41 | status EntryStatus 42 | title Text 43 | format Format 44 | preamble Textarea Maybe 45 | body Textarea Maybe 46 | citation Textarea Maybe 47 | titleHtml Text 48 | bodyHtml Text 49 | featured Bool default=False 50 | 51 | File 52 | userId UserId OnDeleteCascade 53 | format Format 54 | inserted UTCTime 55 | description Text 56 | 57 | Maintenance 58 | userId UserId OnDeleteCascade 59 | from UTCTime 60 | duration Int 61 | deriving Show 62 | 63 | Email json 64 | userId UserId Maybe OnDeleteCascade 65 | address Text 66 | verkey Text Maybe 67 | verified Bool 68 | inserted UTCTime default=CURRENT_TIME 69 | client String Maybe 70 | UniqueEmail address 71 | deriving Show Read Eq 72 | 73 | Login --via third parties 74 | userId UserId Maybe OnDeleteCascade 75 | ident Text 76 | plugin Text 77 | token Text Maybe 78 | verified Bool 79 | inserted UTCTime default=CURRENT_TIME 80 | UniqueLogin plugin ident 81 | 82 | User json 83 | --ident Text 84 | name Text 85 | password Text Maybe 86 | inserted UTCTime default=CURRENT_TIME 87 | logged UTCTime default=CURRENT_TIME 88 | --modified UTCTime -- change the ident 89 | avatar Text Maybe -- url 90 | email Text Maybe -- the email to receive notifications 91 | defaultFormat Format 92 | defaultPreamble Textarea Maybe 93 | defaultCitation Textarea Maybe 94 | --UniqueUser ident 95 | deriving Typeable Show 96 | -------------------------------------------------------------------------------- /config/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | -------------------------------------------------------------------------------- /config/routes.yesodroutes: -------------------------------------------------------------------------------- 1 | -- By default this file is used by `parseRoutesFile` in Foundation.hs 2 | -- Syntax for this file here: https://www.yesodweb.com/book/routing-and-handlers 3 | 4 | /static StaticR Static appStatic 5 | /auth AuthR Auth getAuth 6 | 7 | /favicon.ico FaviconR GET 8 | /robots.txt RobotsR GET 9 | 10 | /maintenance MaintenanceR GET POST 11 | 12 | / HomeR GET POST 13 | /entries EntriesR GET 14 | /feedback FeedbackR GET POST 15 | /parser/from/#Text/to/#Text ParseR POST 16 | /help/#Text EditHelpR GET 17 | /users UsersR GET 18 | /user/#UserId UserHomeR GET !user 19 | /user/#UserId/entries UserEntriesR GET !user 20 | 21 | --/user/#UserId/entries EntriesR GET !user 22 | /entry NewUserEntryR GET POST !user !login 23 | /user/#UserId/entry/#EntryId UserEntryR GET !user 24 | /user/#UserId/entry/#EntryId/pdf DownloadR GET !login 25 | /entry/#EntryId/edit EditUserEntryR GET POST !user !admin 26 | /about/edit EditUserAboutR GET POST !user !admin 27 | 28 | /user/#UserId/categories CategoriesR GET !user 29 | /category/#EntryId/edit EditCategoryR POST DELETE !user !admin 30 | /category NewCategoryR POST !user !login 31 | /tree/node/#EntryId TreeR POST !login 32 | /vote/#EntryId VoteR POST 33 | --/redirect RedirectR GET 34 | 35 | /files FilesR GET POST !user !login 36 | /file/#FileId FileR DELETE !admin 37 | 38 | /settings SettingsR GET POST !user !login 39 | /setting/account AccountR GET POST !user !login 40 | /setting/email/#EmailId EmailSettingR GET POST !user !admin 41 | /setting/login/#LoginId LoginSettingR GET POST !user !admin 42 | 43 | /subscriptions/#EmailId SubscriptionsR GET !user 44 | /subscription/user/#UserSubscriptionId EditUserSubscriptionR GET POST 45 | /subscribe/user/#UserId NewUserSubscriptionR POST 46 | /subscription/entry/#EntrySubscriptionId EditEntrySubscriptionR GET POST 47 | /subscribe/entry/#EntryId NewEntrySubscriptionR POST 48 | 49 | /comment/#EntryId/edit EditCommentR POST DELETE !login 50 | /feedback/#EntryId/edit EditFeedbackR POST DELETE !login 51 | /user/#UserId/comments CommentsR GET !user 52 | 53 | /maintain/entry/#EntryId MaintainEntryR GET POST 54 | /edit/entry/#EntryId EditEntryR GET POST 55 | /edit/page/#Text EditPageR GET POST 56 | --/page/#Text/edit EditUserPageR GET POST !user 57 | /pages PagesR GET 58 | /tool/#Text ToolR GET POST 59 | /slug SlugR GET POST 60 | 61 | !/#Text PageR GET 62 | --!/user/#UserId/#Text UserPageR GET !user 63 | 64 | 65 | -------------------------------------------------------------------------------- /config/settings.yml: -------------------------------------------------------------------------------- 1 | # Values formatted like "_env:YESOD_ENV_VAR_NAME:default_value" can be overridden by the specified environment variable. 2 | # See https://github.com/yesodweb/yesod/wiki/Configuration#overriding-configuration-values-with-environment-variables 3 | 4 | static-root: "_env:YESOD_STATIC_ROOT:http://localhost:3000/static" 5 | static-dir: "_env:YESOD_STATIC_DIR:static" 6 | cache-dir: "_env:YESOD_CACHE_DIR:cache" 7 | host: "_env:YESOD_HOST:*4" # any IPv4 host 8 | #port: "_env:YESOD_PORT:3000" # NB: The port `yesod devel` uses is distinct from this value. Set the `yesod devel` port from the command line. 9 | # For `keter` user, enable the follwing line, and comment out previous one. 10 | port: "_env:PORT:3000" # `keter` uses `PORT` env var name 11 | 12 | ip-from-header: "_env:YESOD_IP_FROM_HEADER:false" 13 | 14 | # Default behavior: determine the application root from the request headers. 15 | # Uncomment to set an explicit approot 16 | #approot: "_env:YESOD_APPROOT:http://localhost:3000" 17 | 18 | # By default, `yesod devel` runs in development, and built executables use 19 | # production settings (see below). To override this, use the following: 20 | # 21 | # development: false 22 | 23 | # Optional values with the following production defaults. 24 | # In development, they default to the inverse. 25 | # 26 | # detailed-logging: false 27 | # should-log-all: false 28 | # reload-templates: false 29 | # mutable-static: false 30 | # skip-combining: false 31 | # auth-dummy-login : false 32 | 33 | # NB: If you need a numeric value (e.g. 123) to parse as a String, wrap it in single quotes (e.g. "_env:YESOD_PGPASS:'123'") 34 | # See https://github.com/yesodweb/yesod/wiki/Configuration#parsing-numeric-values-as-strings 35 | 36 | database: 37 | # See config/test-settings.yml for an override during tests 38 | database: "_env:YESOD_SQLITE_DATABASE:functor-network.sqlite3" 39 | poolsize: "_env:YESOD_SQLITE_POOLSIZE:10" 40 | 41 | copyright: Insert copyright statement here 42 | analytics: "_env:YESOD_ANALYTICS:UA-XXXXX-X" 43 | 44 | #Email config 45 | email-password: "_env:YESOD_EMAIL_PASSWORD:password" 46 | email-host: "_env:YESOD_EMAIL_HOST:domian.com" 47 | email-user: "_env:YESOD_EMAIL_USER:yourname@domian.com" 48 | administrator-email: "_env:YESOD_ADMINISTRATOR_EMAIL:yourname@domian.com" 49 | 50 | #Google 51 | google-client-id: "_env:YESOD_GOOGLE_CLIENT_ID:clientId" 52 | google-client-secret: "_env:YESOD_GOOGLE_CLIENT_SECRET:clientSecret" 53 | 54 | #ORCID 55 | orcid-client-id: "_env:YESOD_ORCID_CLIENT_ID:clientId" 56 | orcid-client-secret: "_env:YESOD_ORCID_CLIENT_SECRET:clientSecret" 57 | -------------------------------------------------------------------------------- /config/test-settings.yml: -------------------------------------------------------------------------------- 1 | database: 2 | # NOTE: By design, this setting prevents the SQLITE_DATABASE environment variable 3 | # from affecting test runs, so that we don't accidentally affect the 4 | # production database during testing. If you're not concerned about that and 5 | # would like to have environment variable overrides, you could instead use 6 | # something like: 7 | # 8 | # database: "_env:SQLITE_DATABASE:functor-network_test.sqlite3" 9 | database: functor-network_test.sqlite3 10 | 11 | auth-dummy-login: true 12 | -------------------------------------------------------------------------------- /package.yaml: -------------------------------------------------------------------------------- 1 | name: functor-network 2 | version: "3.2.1" 3 | 4 | dependencies: 5 | 6 | - base >=4.9.1.0 && <5 7 | - yesod >=1.6 && <1.7 8 | - yesod-core >=1.6 && <1.7 9 | - yesod-auth >=1.6 && <1.7 10 | - yesod-static >=1.6 && <1.7 11 | - yesod-form >=1.6 && <1.8 12 | - classy-prelude >=1.5 && <1.6 13 | - classy-prelude-conduit >=1.5 && <1.6 14 | - classy-prelude-yesod >=1.5 && <1.6 15 | - bytestring >=0.10 && <0.12 16 | - text >=0.11 && <2.0 17 | - persistent >=2.9 && <2.14 18 | - persistent-sqlite >=2.9 && <2.14 19 | - persistent-template >=2.5 && <2.14 20 | - template-haskell 21 | - shakespeare >=2.0 && <2.1 22 | - hjsmin >=0.1 && <0.3 23 | - monad-control >=0.3 && <1.1 24 | - wai-extra >=3.0 && <3.2 25 | - yaml >=0.11 && <0.12 26 | - http-client-tls >=0.3 && <0.4 27 | - http-conduit >=2.3 && <2.4 28 | - directory >=1.1 && <1.4 29 | - warp >=3.0 && <3.4 30 | - data-default 31 | - aeson >=1.4 && <2.1 32 | - conduit >=1.0 && <2.0 33 | - monad-logger >=0.3 && <0.4 34 | - fast-logger >=2.2 && <3.2 35 | - wai-logger >=2.2 && <2.5 36 | - file-embed 37 | - safe 38 | - unordered-containers 39 | - containers 40 | - vector 41 | - time 42 | - case-insensitive 43 | - wai 44 | - foreign-store 45 | #- regex-posix==0.96.* 46 | #- regex-compat==0.95.* 47 | - regex==1.1.* 48 | - process==1.6.* 49 | - mime-mail == 0.5.* 50 | - smtp-mail == 0.3.* 51 | - blaze-html== 0.9.* 52 | - extra==1.7.* 53 | - yesod-auth-oauth2==0.7.* 54 | - filepath==1.4.* 55 | - random==1.2.* 56 | - scalpel==0.6.* 57 | - nonce==1.0.* 58 | - html-conduit==1.3.* 59 | - xml-conduit==1.9.* 60 | #- zip 61 | - unix==2.7.* 62 | - split==0.2.* 63 | - async==2.2.* 64 | - tagsoup==0.14.* 65 | 66 | 67 | # The library contains all of our application code. The executable 68 | # defined below is just a thin wrapper. 69 | library: 70 | source-dirs: src 71 | when: 72 | - condition: (flag(dev)) || (flag(library-only)) 73 | then: 74 | ghc-options: 75 | - -Wall 76 | - -fwarn-tabs 77 | - -O0 78 | cpp-options: -DDEVELOPMENT 79 | else: 80 | ghc-options: 81 | - -Wall 82 | - -fwarn-tabs 83 | - -O2 84 | 85 | # Runnable executable for our application 86 | executables: 87 | functor-network: 88 | main: main.hs 89 | source-dirs: app 90 | ghc-options: 91 | - -threaded 92 | - -rtsopts 93 | - -with-rtsopts=-N 94 | dependencies: 95 | - functor-network 96 | when: 97 | - condition: flag(library-only) 98 | buildable: false 99 | 100 | # Test suite 101 | tests: 102 | functor-network-test: 103 | main: Spec.hs 104 | source-dirs: test 105 | ghc-options: -Wall 106 | dependencies: 107 | - functor-network 108 | - hspec >=2.0.0 109 | - yesod-test 110 | - microlens 111 | 112 | # Define flags used by "yesod devel" to make compilation faster 113 | flags: 114 | library-only: 115 | description: Build for use with "yesod devel" 116 | manual: false 117 | default: false 118 | dev: 119 | description: Turn on development settings, like auto-reload templates. 120 | manual: false 121 | default: false 122 | -------------------------------------------------------------------------------- /src/Handler/Account.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE QuasiQuotes #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | {-# LANGUAGE NoImplicitPrelude #-} 4 | 5 | 6 | module Handler.Account where 7 | 8 | import Import 9 | import Yesod.Form.Bootstrap3 10 | import Handler.EditComment (deleteEntryRecursive) 11 | 12 | confirmationForm :: Form Text 13 | confirmationForm = renderBootstrap3 BootstrapBasicForm $ areq textField (bfs ("Confirmation"::Text)) Nothing 14 | 15 | getAccountR :: Handler Html 16 | getAccountR = do 17 | 18 | (widget, enctype) <- generateFormPost confirmationForm 19 | defaultLayout $ do 20 | setTitleI MsgAccount 21 | [whamlet| 22 |
Not satisfied with our platform? A better way than just leaving is to give us feedback. We are always looking for ways to improve. 24 |
_{MsgUnregistrationWarning} 25 |
_{MsgUserUnregistrationConfirmation} 26 |