Skip to content

Commit

Permalink
initial ical changes
Browse files Browse the repository at this point in the history
* does not compile
* still needs to output multiple ical files
  • Loading branch information
0rphee committed Jun 5, 2024
1 parent bcf3218 commit 068a87b
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 13 deletions.
2 changes: 2 additions & 0 deletions package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ dependencies:
- time
- optparse-applicative
- deepseq
- iCalendar
- data-default

ghc-options:
- -Wall
Expand Down
11 changes: 10 additions & 1 deletion schedule-maker.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 1.12

-- This file has been generated from package.yaml by hpack version 0.35.2.
-- This file has been generated from package.yaml by hpack version 0.36.0.
--
-- see: https://github.com/sol/hpack

Expand Down Expand Up @@ -30,6 +30,7 @@ executable schedule-maker
PPrint
Types
Validation
WriteiCal
WriteXlsx
Paths_schedule_maker
hs-source-dirs:
Expand All @@ -48,7 +49,9 @@ executable schedule-maker
, base >=4.7 && <5
, bytestring
, containers
, data-default
, deepseq
, iCalendar
, lens
, optparse-applicative
, prettyprinter
Expand All @@ -68,6 +71,7 @@ test-suite schedule-maker-test
PPrint
Types
Validation
WriteiCal
WriteXlsx
Paths_schedule_maker
hs-source-dirs:
Expand All @@ -86,7 +90,9 @@ test-suite schedule-maker-test
, base >=4.7 && <5
, bytestring
, containers
, data-default
, deepseq
, iCalendar
, lens
, optparse-applicative
, prettyprinter
Expand All @@ -106,6 +112,7 @@ benchmark xolsh-benchmarks
PPrint
Types
Validation
WriteiCal
WriteXlsx
Paths_schedule_maker
hs-source-dirs:
Expand All @@ -124,7 +131,9 @@ benchmark xolsh-benchmarks
, base >=4.7 && <5
, bytestring
, containers
, data-default
, deepseq
, iCalendar
, lens
, optparse-applicative
, prettyprinter
Expand Down
25 changes: 23 additions & 2 deletions src/CmdLineOpts.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{-# LANGUAGE LambdaCase #-}

module CmdLineOpts (options, Options (..), execParser, ExampleYamlLanguage (..)) where
module CmdLineOpts (options, Options (..), execParser, ExampleYamlLanguage (..),) where

import Options.Applicative

Expand All @@ -9,6 +9,7 @@ data Options
!FilePath -- yamlSource
!Bool -- prettyPrintToStdout
!FilePath -- outputFilePath
!(Maybe FilePath) -- create *.ical schedule
| PrintExampleYaml !ExampleYamlLanguage -- True english, False spanish

data ExampleYamlLanguage
Expand All @@ -32,7 +33,7 @@ options =
opts = languageParser <|> normalOpts

normalOpts :: Parser Options
normalOpts = NormalOptions <$> yamlPath <*> prettyPrintStdout <*> outputPath
normalOpts = NormalOptions <$> yamlPath <*> prettyPrintStdout <*> outputPath <*> icalPath

languageParser :: Parser Options
languageParser =
Expand Down Expand Up @@ -79,3 +80,23 @@ outputPath =
<> long "output"
<> short 'o'
)

icalPath :: Parser (Maybe FilePath)
icalPath = optional first <|> second
where first =
strOption
( metavar "FILENAME"
<> help "Write output to FILE (.ical)"
<> action "directory"
<> action "file"
<> long "ical"
<> short 'i'
)
second =
flag Nothing (Just "schedules.ical")
(
help "Write output to FILE (.ical)"
<> long "ical"
<> short 'i'

)
21 changes: 20 additions & 1 deletion src/Types.hs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}

module Types
( Class (..),
Hour (..),
Minute (..),
Time (..),
Interval (..),
Subject (..),
IDandSubj (..),
Error (..),
minuteToInt,
getClassDayOffset,
)
where

Expand Down Expand Up @@ -86,7 +90,7 @@ data Hour
| H21
| H22
| H23
deriving (Eq, Ord, Bounded)
deriving (Eq, Ord, Enum, Bounded)

instance NFData Hour where
rnf h = h `seq` ()
Expand Down Expand Up @@ -488,3 +492,18 @@ instance Pretty Error where
<> pretty subjId
<> line
<> indent 2 (vsep [pretty subj1, pretty subj2])

minuteToInt :: Minute -> Int
minuteToInt = \case
ZeroMinutes -> 0
HalfAnHour -> 30

getClassDayOffset :: Class -> Integer
getClassDayOffset = \case
MondayClass _ -> 0
TuesdayClass _ -> 1
WednesdayClass _ -> 2
ThursdayClass _ -> 3
FridayClass _ -> 4
SaturdayClass _ -> 5
SundayClass _ -> 6
5 changes: 4 additions & 1 deletion src/Validation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import System.Console.Terminal.Size
import System.IO (stdout)
import Types
import WriteXlsx (saveExcel)
import WriteiCal (saveICal)

intervalsOverlap :: Interval -> Interval -> Bool
intervalsOverlap (MkInterval a b) (MkInterval x y)
Expand Down Expand Up @@ -123,7 +124,7 @@ collectValidationResults xs = do
runProgLogic :: Options -> IO ()
runProgLogic = \case
PrintExampleYaml lang -> printYaml lang
NormalOptions yamlSource prettyPrintToStdout outputFilePath -> do
NormalOptions yamlSource prettyPrintToStdout outputFilePath mayICalFilePath -> do
res <- decodeFileEither yamlSource -- "test-english.yaml"
sz <-
size >>= \case
Expand All @@ -139,4 +140,6 @@ runProgLogic = \case
Left errs -> prettyRender (annotateErrors errs) -- validation errors
Right lists -> do
when prettyPrintToStdout $ prettyRender (annotateSubjectLists lists)

maybe (pure ()) (saveICal lists) mayICalFilePath
saveExcel lists outputFilePath
146 changes: 146 additions & 0 deletions src/WriteiCal.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}

module WriteiCal (saveICal) where

import Data.ByteString.Lazy.Char8 qualified as BSL
import Data.Default
import Data.Function ((&))
import Data.Map.Strict as M
import Data.Text qualified as TS
import Data.Text.Lazy qualified as TL
import Data.Time
import Data.Time.Calendar.Easter (sundayAfter)
import Data.Time.Clock.System (getSystemTime, systemToUTCTime)
import Text.ICalendar hiding (Class)
import Types

emptyVCalendar :: VCalendar
emptyVCalendar = def

emptyVEvent :: VEvent
emptyVEvent =
VEvent
{ veDTStamp = DTStamp (UTCTime (ModifiedJulianDay 1) (secondsToDiffTime 1)) def, -- date & time of creation
veUID = UID "" def,
veClass = def,
veDTStart = def,
veCreated = def,
veDescription = def,
veGeo = def,
veLastMod = def,
veLocation = def,
veOrganizer = def,
vePriority = def,
veSeq = def,
veStatus = def,
veSummary = def,
veTransp = def,
veUrl = def,
veRecurId = def,
veRRule = def,
veDTEndDuration = def,
veAttach = def,
veAttendee = def,
veCategories = def,
veComment = def,
veContact = def,
veExDate = def,
veRStatus = def,
veRelated = def,
veResources = def,
veRDate = def,
veAlarms = def,
veOther = def
}

toVCal :: Day -> [IDandSubj] -> VCalendar
toVCal weekStartDay subjects =
emptyVCalendar
{ vcEvents = vEventMap
}
where
vEventMap :: Map (TL.Text, Maybe (Either Date DateTime)) VEvent
vEventMap = ((\(txt, ev) -> ((txt, Nothing), ev)) <$> vEventList) & M.fromList

vEventList :: [(TL.Text, VEvent)]
vEventList = concatMap idandsubjToVEvents subjects

idandsubjToVEvents :: IDandSubj -> [(TL.Text, VEvent)]
idandsubjToVEvents (IDandSubj (subId, subj)) = fmap (classToEvent subId subj.subjName subj.subjProfessor) subj.subjclasses

classToEvent :: TS.Text -> TS.Text -> TS.Text -> Class -> (TL.Text, VEvent) -- T.Text: UID value
classToEvent subId name teacher individualClass =
( uidText,
emptyVEvent
{ veSummary =
Just $
Summary
{ summaryValue = TL.fromStrict (name <> "(" <> subId <> ")"),
summaryLanguage = def,
summaryAltRep = def,
summaryOther = def
},
veUID = UID uidText def,
veDTStart = Just startDatetime,
veDTEndDuration = Just $ Left endDatetime,
veDescription =
Just $
Description
{ descriptionValue = TL.fromStrict teacher,
descriptionLanguage = def,
descriptionAltRep = def,
descriptionOther = def
}
}
)
where
uidText :: TL.Text
uidText = TL.fromStrict subId <> TL.pack (show $ getClassDayOffset individualClass)

dayOfClass :: Day
dayOfClass = addDays (getClassDayOffset individualClass) weekStartDay

startDatetime :: DTStart
startDatetime =
DTStartDateTime
{ dtStartDateTimeValue = buildDateTime individualClass.classInterval.intervalStartingTime,
dtStartOther = def
}
endDatetime :: DTEnd
endDatetime =
DTEndDateTime
{ dtEndDateTimeValue = buildDateTime individualClass.classInterval.intervalEndTime,
dtEndOther = def
}
buildDateTime :: Time -> DateTime
buildDateTime time =
FloatingDateTime $
LocalTime
{ localDay = dayOfClass,
localTimeOfDay =
TimeOfDay
{ todHour = fromEnum time.timeHour,
todMin = minuteToInt time.timeMinute,
todSec = 0
}
}

getLocalTime :: IO LocalTime
getLocalTime = do
utcTime <- systemToUTCTime <$> getSystemTime
timezone <- getTimeZone utcTime
pure $ utcToLocalTime timezone utcTime

renderICal :: [IDandSubj] -> IO BSL.ByteString
renderICal idAndSubj = do
(LocalTime today _) <- getLocalTime
let nextMonday = addDays 1 $ sundayAfter today
let vcal = toVCal nextMonday idAndSubj
pure $ printICalendar def vcal


saveICal :: [IDandSubj] -> FilePath -> IO ()
saveICal idAndSubj filepath = do
renderedICal <- renderICal idAndSubj
BSL.writeFile filepath renderedICal
10 changes: 7 additions & 3 deletions stack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
#
# resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2018-01-01.yaml
resolver: nightly-2023-09-09
compiler: ghc-9.6.2
resolver: lts-22.23
# compiler: ghc-9.4.8

# User packages to be built.
# Various formats can be used as shown in the example below.
Expand All @@ -43,7 +43,11 @@ ghc-options:
# - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
#
# extra-deps: []
extra-deps:
- git: git@github.com:0rphee/iCalendar.git
commit: "b31ccf7c1f68532f5c6beb0e50128290fa5d03f3"
- mime-0.4.0.2@sha256:208947d9d1a19d08850be67ecb28c6e776db697f3bba05bd9d682e51a59f241f,983


# Override default flag values for local packages and extra-deps
# flags: {}
Expand Down
28 changes: 23 additions & 5 deletions stack.yaml.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,28 @@
# For more information, please see the documentation at:
# https://docs.haskellstack.org/en/stable/lock_files

packages: []
packages:
- completed:
commit: b31ccf7c1f68532f5c6beb0e50128290fa5d03f3
git: git@github.com:0rphee/iCalendar.git
name: iCalendar
pantry-tree:
sha256: 3c93da66cbb54febeadf033a3153f08ffb90b951b67e7b513a2ba052bc7646a1
size: 1026
version: 0.4.0.5
original:
commit: b31ccf7c1f68532f5c6beb0e50128290fa5d03f3
git: git@github.com:0rphee/iCalendar.git
- completed:
hackage: mime-0.4.0.2@sha256:208947d9d1a19d08850be67ecb28c6e776db697f3bba05bd9d682e51a59f241f,983
pantry-tree:
sha256: f2529a2e1678074ca0340ff60caa986f4e246d7d9abe8186657910c2900364bb
size: 565
original:
hackage: mime-0.4.0.2@sha256:208947d9d1a19d08850be67ecb28c6e776db697f3bba05bd9d682e51a59f241f,983
snapshots:
- completed:
sha256: a4e61f552492f4f0a14246c054144a8b6b455c67c9e99fddf891d009baa65604
size: 667656
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2023/9/9.yaml
original: nightly-2023-09-09
sha256: 73ad581de7c5306278aec7706cafaf3b1c2eb7abf4ab586e4d9dc675c6106c4e
size: 718708
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/23.yaml
original: lts-22.23

0 comments on commit 068a87b

Please sign in to comment.