Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
- Refactor graph helper functions from `app/Svg/Database.hs` to `app/Models/Graph.hs`
- Refactor functions for performing matrix operations from `app/Svg/Parser.hs` to `app/Util/Matrix.hs`
- Updated documentation in `app/Util/Blaze.hs`
- Removed `SvgJSON` data type in favour of `([Text], [Shape], [Path])`

## [0.7.2] - 2025-12-10

Expand Down
6 changes: 3 additions & 3 deletions app/Controllers/Graph.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Controllers.Graph (graphResponse, index, getGraphJSON, graphImageResponse, saveGraphJSON) where

import Control.Monad.IO.Class (liftIO)
import Data.Aeson (decode, object, (.=))
import Data.Aeson (object, (.=))
import Data.Maybe (fromMaybe)
import Export.ImageConversion (withImageFile)
import Happstack.Server (Response, ServerPart, lookBS, lookText', ok, toResponse)
Expand All @@ -15,7 +15,7 @@ import qualified Text.Blaze.Html5.Attributes as A

import Config (runDb)
import Database.Persist.Sqlite (Entity, SelectOpt (Asc), SqlPersistM, selectList, (==.))
import Database.Tables as Tables (EntityField (GraphDynamic, GraphTitle), Graph, SvgJSON, Text)
import Database.Tables as Tables (EntityField (GraphDynamic, GraphTitle), Graph, Text, parseGraphJSON)
import Export.GetImages (writeActiveGraphImage)
import Models.Graph (getGraph, insertGraph)
import Util.Happstack (createJSONResponse)
Expand Down Expand Up @@ -64,7 +64,7 @@ saveGraphJSON :: ServerPart Response
saveGraphJSON = do
jsonStr <- lookBS "jsonData"
nameStr <- lookText' "nameData"
let jsonObj = decode jsonStr :: Maybe SvgJSON
let jsonObj = parseGraphJSON jsonStr
case jsonObj of
Nothing -> return $ toResponse ("Error" :: String)
Just svg -> do
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename svg into components

Expand Down
29 changes: 15 additions & 14 deletions app/Database/Tables.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ straightforward.

module Database.Tables where

import Data.Aeson (FromJSON (parseJSON), ToJSON (toJSON), genericToJSON, withObject, (.!=), (.:),
(.:?))
import Data.Aeson.Types (Options (..), Parser, Value (Object), defaultOptions)
import Data.Aeson (FromJSON (parseJSON), ToJSON (toJSON), decode, genericToJSON, withObject,
(.!=), (.:), (.:?))
import Data.Aeson.Types (Options (..), Parser, Value (Object), defaultOptions, parseMaybe)
import Data.Char (toLower)
import qualified Data.Text as T
import qualified Data.ByteString.Lazy as L
import Data.Time.Clock (UTCTime)
import Database.DataType
import Database.Persist.Sqlite (Key, SqlPersistM, entityVal, selectFirst, (==.))
Expand Down Expand Up @@ -161,13 +162,6 @@ SchemaVersion

-- ** TODO: Remove these extra types and class instances

-- | JSON SVG data
data SvgJSON =
SvgJSON { texts :: [Text],
shapes :: [Shape],
paths :: [Path]
} deriving (Show, Generic)

data Time' =
Time' { weekDay' :: Double,
startHour' :: Double,
Expand Down Expand Up @@ -211,10 +205,6 @@ instance ToJSON Time
instance ToJSON MeetTime'
instance ToJSON Building

-- instance FromJSON required so that tables can be parsed into JSON,
-- not necessary otherwise.
instance FromJSON SvgJSON

instance ToJSON Meeting where
toJSON = genericToJSON defaultOptions {
fieldLabelModifier =
Expand Down Expand Up @@ -278,6 +268,17 @@ parseInstr (Object io) = do
return (T.concat [firstName, ". ", lastName])
parseInstr _ = return ""

-- | Parse the JSON representation of a graph into its texts, shapes, and paths components.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to parseGraphComponentsJSON and move this into the graph model file

parseGraphJSON :: L.ByteString -> Maybe ([Text], [Shape], [Path])
parseGraphJSON jsonStr = do
obj <- decode jsonStr
parseMaybe (\o -> do
texts <- o .: "texts"
shapes <- o .: "shapes"
paths <- o .: "paths"
return (texts, shapes, paths)
) obj

-- | Converts the miliseconds time into hourly time
-- | Assumes times are rounded to the nearest hour
getHourVal :: Int -> Double
Expand Down
10 changes: 5 additions & 5 deletions app/Models/Graph.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Database.DataType (ShapeType (BoolNode, Hybrid, Node))
import Database.Persist.Sqlite (Entity, PersistEntity, PersistValue (PersistInt64), SqlPersistM,
deleteWhere, entityKey, entityVal, insert, insert_, insertMany_, keyToValues,
selectFirst, selectList, (<-.), (==.))
import Database.Tables hiding (paths, shapes, texts)
import Database.Tables
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the Database.Tables imports you changed so that they explicitly name what's being imported (this will help improve the code quality throughout)

import Svg.Builder (buildEllipses, buildPath, buildRect)
import Util.Helpers

Expand Down Expand Up @@ -55,10 +55,10 @@ getGraph graphName = runDb $ do

-- | Insert a new graph into the database, given its SVG JSON.
-- | Return Nothing.
insertGraph :: T.Text -- ^ The title of the graph being inserted.
-> SvgJSON -- ^ The SVG JSON data of the inserted graph (texts, shapes, paths).
-> SqlPersistM () -- ^ Return Nothing.
insertGraph nameStr_ (SvgJSON texts shapes paths) = do
insertGraph :: T.Text -- ^ The title of the graph being inserted.
-> ([Text], [Shape], [Path]) -- ^ The parsed JSON data of the inserted graph.
-> SqlPersistM () -- ^ Return Nothing.
insertGraph nameStr_ (texts, shapes, paths) = do
gId <- insert $ Graph nameStr_ 256 256 False
insertMany_ $ map (\text -> text {textGraph = gId}) texts
insertMany_ $ map (\shape -> shape {shapeGraph = gId}) shapes
Expand Down
2 changes: 1 addition & 1 deletion app/Svg/Builder.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import Data.Char (toLower)
import Data.List (find)
import qualified Data.Text as T
import Database.DataType
import Database.Tables hiding (shapes, texts)
import Database.Tables
import Util.Matrix (matrixPointMultiply)
import TextShow (showt)
import Util.Helpers
Expand Down
2 changes: 1 addition & 1 deletion app/Svg/Generator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import Data.Maybe (fromMaybe)
import qualified Data.Text as T
import Database.DataType
import Database.Persist.Sqlite
import Database.Tables hiding (paths, texts)
import Database.Tables
import Svg.Builder
import System.IO (Handle, hPutStrLn)
import Text.Blaze (toMarkup)
Expand Down
2 changes: 1 addition & 1 deletion app/Svg/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import qualified Data.Text as T
import Data.Text.IO as T (readFile)
import Database.DataType
import Database.Persist.Sqlite
import Database.Tables hiding (graphHeight, graphWidth, paths, shapes, texts)
import Database.Tables hiding (graphHeight, graphWidth)
import Models.Graph (deleteExistingGraph, insertElements)
import qualified Text.HTML.TagSoup as TS hiding (fromAttrib)
import Text.HTML.TagSoup (Tag)
Expand Down
16 changes: 8 additions & 8 deletions backend-test/Controllers/GraphControllerTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import qualified Data.Aeson.KeyMap as KeyMap
import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.Text as T
import Database.Persist.Sqlite (SqlPersistM, insert_, toSqlKey)
import Database.Tables (Graph (..), Path (..), Shape (..), Text (..), SvgJSON (..))
import Database.Tables (Graph (..), Path (..), Shape (..), Text (..), parseGraphJSON)
import Happstack.Server (rsBody)
import Models.Graph (getGraph, insertGraph)
import Test.Tasty (TestTree)
Expand Down Expand Up @@ -187,16 +187,16 @@ runGetGraphJSONTest (label, (texts', shapes', paths')) =
let graphName = "Test Graph Name"
runDb $ do
clearDatabase
insertGraph graphName (SvgJSON texts' shapes' paths')
insertGraph graphName (texts', shapes', paths')
response <- runServerPartWith Controllers.Graph.getGraphJSON $ mockGetRequest "/get-json-data" [("graphName", T.unpack graphName)] ""
let body = rsBody response
let jsonObj = decode body :: Maybe SvgJSON
let jsonObj = parseGraphJSON body
case jsonObj of
Nothing -> assertFailure ("Maybe SvgJSON returned as Nothing for " ++ label)
Just svg -> do
assertEqual ("Texts differ for " ++ label) texts' (map (\text -> text {textGraph = toSqlKey 1}) (texts svg))
assertEqual ("Shapes differ for " ++ label) shapes' (map (\shape -> shape {shapeGraph = toSqlKey 1}) (shapes svg))
assertEqual ("Paths differ for " ++ label) paths' (map (\path -> path {pathGraph = toSqlKey 1}) (paths svg))
Nothing -> assertFailure ("Maybe ([Text], [Shape], [Path]) returned as Nothing for " ++ label)
Just (parsedTexts, parsedShapes, parsedPaths) -> do
assertEqual ("Texts differ for " ++ label) texts' (map (\text -> text {textGraph = toSqlKey 1}) parsedTexts)
assertEqual ("Shapes differ for " ++ label) shapes' (map (\shape -> shape {shapeGraph = toSqlKey 1}) parsedShapes)
assertEqual ("Paths differ for " ++ label) paths' (map (\path -> path {pathGraph = toSqlKey 1}) parsedPaths)

-- | Run all getGraphJSON tests
runGetGraphJSONTests :: [TestTree]
Expand Down