-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBrowserWorkspaceStore.hs
101 lines (92 loc) · 3.94 KB
/
BrowserWorkspaceStore.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -Wno-missing-signatures -Wno-unused-top-binds #-}
{-# OPTIONS_GHC -Wno-name-shadowing -Wno-unused-do-bind #-}
module BrowserWorkspaceStore where
import Control.Monad (forM_)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Aeson (FromJSON, eitherDecode, encode)
import qualified Data.ByteString.Lazy.UTF8 as UTF8
import Data.JSString (JSString, pack, unpack)
import Data.List (isPrefixOf)
import Data.Maybe (fromJust, isJust)
import JavaScript.Web.Storage (getIndex, getItem, getLength,
localStorage, removeItem, setItem)
import MoneySplit (Actions (Actions))
import Text.Printf (printf)
import WorkspaceStore
data BrowserWorkspaceStore = BrowserWorkspaceStore deriving Show
workspaceKey workspaceName = pack $ "workspace_" ++ workspaceName
setJson key value = liftIO $ do
setItem
key
(pack . UTF8.toString . encode $ value)
localStorage
getJson :: (MonadIO m, FromJSON a)
=> JSString -> m (Either String a)
getJson key = liftIO $ do
strMaybe <- getItem key localStorage
case strMaybe of
Just str -> do
let bs = UTF8.fromString . unpack $ str
return . eitherDecode $ bs
Nothing -> return . Left $ printf "Workpace key '%s' doesn't exist'" (unpack key)
getIndexStr :: MonadIO m => Int -> m (Maybe String)
getIndexStr i = liftIO $ do
jsStrMaybe <- getIndex i localStorage
return $ fmap unpack jsStrMaybe
migrateBrowserWorkspaceStore finalMigrationStep = do
liftIO $ do
strMaybe <- getItem (pack . UTF8.toString $ "splitActions") localStorage
case strMaybe of
Just str -> do
setItem (workspaceKey defaultWorkspaceName) str localStorage
removeItem (pack . UTF8.toString $ "splitActions") localStorage
Nothing -> return ()
-- Make sure we can read all workspaces: Delete unreadable workspaces.
wss <- getWorkspaces BrowserWorkspaceStore
forM_ wss $ \ws -> do
let (WorkspaceId wsName) = workspaceId ws
actions :: Either String Actions <- getJson (workspaceKey wsName)
case actions of
Right _ -> return ()
Left err -> do
liftIO . putStrLn
$ printf
( "Failed to parse actions for workspace '%s' "
++ "deleting the workspace, error: %s" )
wsName err
deleteWorkspace BrowserWorkspaceStore (workspaceId ws)
workspaceStoreCleanup BrowserWorkspaceStore finalMigrationStep
instance WorkspaceStore BrowserWorkspaceStore where
createWorkspace _ workspaceName = do
return $ Workspace (WorkspaceId workspaceName) workspaceName
putActions _ (WorkspaceId workspaceName) actions
= setJson (workspaceKey workspaceName) actions
getActions _ (WorkspaceId workspaceName)
= getJson (workspaceKey workspaceName) >>= \case
Left err -> do
liftIO . putStrLn
$ printf
( "Failed to parse actions for workspace '%s' "
++ " returning empty actions, error: %s" )
workspaceName err
return $ Actions [] [] []
Right a -> return a
deleteWorkspace _ (WorkspaceId workspaceName)
= liftIO $ removeItem (workspaceKey workspaceName) localStorage
wipeWorkspace _ (WorkspaceId workspaceName)
= setJson (workspaceKey workspaceName) (Actions [] [] [])
getWorkspaces _ = liftIO $ do
len <- getLength localStorage
let prefix = "workspace_"
prefixLength = length prefix
names <- map (drop prefixLength)
. filter (prefix `isPrefixOf`)
. map fromJust
. filter isJust
<$> mapM getIndexStr [0..len - 1]
return $ zipWith Workspace (map WorkspaceId names) names
migrate _ = migrateBrowserWorkspaceStore True