1--------------------------------------------------------------------
2-- |
3-- Module    : Text.Atom.Feed
4-- Copyright : (c) Galois, Inc. 2008,
5--             (c) Sigbjorn Finne 2009-
6-- License   : BSD3
7--
8-- Maintainer: Sigbjorn Finne <sof@forkIO.com>
9-- Stability : provisional
10-- Portability: portable
11--
12--------------------------------------------------------------------
13module Text.Atom.Feed
14  ( URI
15  , NCName
16  , Date
17  , MediaType
18  , Attr
19  , Feed(..)
20  , Entry(..)
21  , EntryContent(..)
22  , Category(..)
23  , Generator(..)
24  , Link(..)
25  , TextContent(..)
26  , txtToString
27  , Source(..)
28  , Person(..)
29  , InReplyTo(..)
30  , InReplyTotal(..)
31  , newCategory
32  , nullFeed
33  , nullEntry
34  , nullGenerator
35  , nullLink
36  , nullSource
37  , nullPerson
38  ) where
39
40import Prelude.Compat
41
42import Data.Text (Text, unpack)
43import Data.XML.Compat
44import Data.XML.Types as XML
45
46-- *Core types
47-- NOTE: In the future we may want to have more structured
48-- types for these.
49type URI = Text
50
51type NCName = Text
52
53type Date = Text
54
55type MediaType = Text
56
57data Feed = Feed
58  { feedId :: URI
59  , feedTitle :: TextContent
60  , feedUpdated :: Date
61  , feedAuthors :: [Person]
62  , feedCategories :: [Category]
63  , feedContributors :: [Person]
64  , feedGenerator :: Maybe Generator
65  , feedIcon :: Maybe URI
66  , feedLinks :: [Link]
67  , feedLogo :: Maybe URI
68  , feedRights :: Maybe TextContent
69  , feedSubtitle :: Maybe TextContent
70  , feedEntries :: [Entry]
71  , feedAttrs :: [Attr]
72  , feedOther :: [XML.Element]
73  } deriving (Show)
74
75data Entry = Entry
76  { entryId :: URI
77  , entryTitle :: TextContent
78  , entryUpdated :: Date
79  , entryAuthors :: [Person]
80  , entryCategories :: [Category]
81  , entryContent :: Maybe EntryContent
82  , entryContributor :: [Person]
83  , entryLinks :: [Link]
84  , entryPublished :: Maybe Date
85  , entryRights :: Maybe TextContent
86  , entrySource :: Maybe Source
87  , entrySummary :: Maybe TextContent
88  , entryInReplyTo :: Maybe InReplyTo
89  , entryInReplyTotal :: Maybe InReplyTotal
90  , entryAttrs :: [Attr]
91  , entryOther :: [XML.Element]
92  } deriving (Show)
93
94data EntryContent
95  = TextContent Text
96  | HTMLContent Text
97  | XHTMLContent XML.Element
98  | MixedContent (Maybe Text)
99                 [XML.Node]
100  | ExternalContent (Maybe MediaType)
101                    URI
102  deriving (Show)
103
104data Category = Category
105  { catTerm :: Text -- ^ the tag\/term of the category.
106  , catScheme :: Maybe URI -- ^ optional URL for identifying the categorization scheme.
107  , catLabel :: Maybe Text -- ^ human-readable label of the category
108  , catOther :: [XML.Element] -- ^ unknown elements, for extensibility.
109  } deriving (Show)
110
111data Generator = Generator
112  { genURI :: Maybe URI
113  , genVersion :: Maybe Text
114  , genText :: Text
115  } deriving (Eq, Show)
116
117data Link = Link
118  { linkHref :: URI
119         -- ToDo: make the switch over to using the Atom.Feed.Link relation type.
120  , linkRel :: Maybe (Either NCName URI)
121  , linkType :: Maybe MediaType
122  , linkHrefLang :: Maybe Text
123  , linkTitle :: Maybe Text
124  , linkLength :: Maybe Text
125  , linkAttrs :: [Attr]
126  , linkOther :: [XML.Element]
127  } deriving (Show)
128
129data TextContent
130  = TextString Text
131  | HTMLString Text
132  | XHTMLString XML.Element
133  deriving (Show)
134
135txtToString :: TextContent -> String
136txtToString (TextString s) = unpack s
137txtToString (HTMLString s) = unpack s
138txtToString (XHTMLString x) = show x
139
140data Source = Source
141  { sourceAuthors :: [Person]
142  , sourceCategories :: [Category]
143  , sourceGenerator :: Maybe Generator
144  , sourceIcon :: Maybe URI
145  , sourceId :: Maybe URI
146  , sourceLinks :: [Link]
147  , sourceLogo :: Maybe URI
148  , sourceRights :: Maybe TextContent
149  , sourceSubtitle :: Maybe TextContent
150  , sourceTitle :: Maybe TextContent
151  , sourceUpdated :: Maybe Date
152  , sourceOther :: [XML.Element]
153  } deriving (Show)
154
155data Person = Person
156  { personName :: Text
157  , personURI :: Maybe URI
158  , personEmail :: Maybe Text
159  , personOther :: [XML.Element]
160  } deriving (Show)
161
162data InReplyTo = InReplyTo
163  { replyToRef :: URI
164  , replyToHRef :: Maybe URI
165  , replyToType :: Maybe MediaType
166  , replyToSource :: Maybe URI
167  , replyToOther :: [Attr]
168  , replyToContent :: [Node]
169  } deriving (Show)
170
171data InReplyTotal = InReplyTotal
172  { replyToTotal :: Integer -- non-negative :)
173  , replyToTotalOther :: [Attr]
174  } deriving (Show)
175
176-- *Smart Constructors
177newCategory ::
178     Text -- ^catTerm
179  -> Category
180newCategory t = Category {catTerm = t, catScheme = Nothing, catLabel = Just t, catOther = []}
181
182nullFeed ::
183     URI -- ^feedId
184  -> TextContent -- ^feedTitle
185  -> Date -- ^feedUpdated
186  -> Feed
187nullFeed i t u =
188  Feed
189    { feedId = i
190    , feedTitle = t
191    , feedUpdated = u
192    , feedAuthors = []
193    , feedCategories = []
194    , feedContributors = []
195    , feedGenerator = Nothing
196    , feedIcon = Nothing
197    , feedLinks = []
198    , feedLogo = Nothing
199    , feedRights = Nothing
200    , feedSubtitle = Nothing
201    , feedEntries = []
202    , feedAttrs = []
203    , feedOther = []
204    }
205
206nullEntry ::
207     URI -- ^entryId
208  -> TextContent -- ^entryTitle
209  -> Date -- ^entryUpdated
210  -> Entry
211nullEntry i t u =
212  Entry
213    { entryId = i
214    , entryTitle = t
215    , entryUpdated = u
216    , entryAuthors = []
217    , entryCategories = []
218    , entryContent = Nothing
219    , entryContributor = []
220    , entryLinks = []
221    , entryPublished = Nothing
222    , entryRights = Nothing
223    , entrySource = Nothing
224    , entrySummary = Nothing
225    , entryInReplyTo = Nothing
226    , entryInReplyTotal = Nothing
227    , entryAttrs = []
228    , entryOther = []
229    }
230
231nullGenerator ::
232     Text -- ^genText
233  -> Generator
234nullGenerator t = Generator {genURI = Nothing, genVersion = Nothing, genText = t}
235
236nullLink ::
237     URI -- ^linkHref
238  -> Link
239nullLink uri =
240  Link
241    { linkHref = uri
242    , linkRel = Nothing
243    , linkType = Nothing
244    , linkHrefLang = Nothing
245    , linkTitle = Nothing
246    , linkLength = Nothing
247    , linkAttrs = []
248    , linkOther = []
249    }
250
251nullSource :: Source
252nullSource =
253  Source
254    { sourceAuthors = []
255    , sourceCategories = []
256    , sourceGenerator = Nothing
257    , sourceIcon = Nothing
258    , sourceId = Nothing
259    , sourceLinks = []
260    , sourceLogo = Nothing
261    , sourceRights = Nothing
262    , sourceSubtitle = Nothing
263    , sourceTitle = Nothing
264    , sourceUpdated = Nothing
265    , sourceOther = []
266    }
267
268nullPerson :: Person
269nullPerson = Person {personName = "", personURI = Nothing, personEmail = Nothing, personOther = []}
270