]> ruin.nu Git - yawbih.git/blob - Wiki.hs
More cleanup
[yawbih.git] / Wiki.hs
1 module Wiki (
2         Backend (getCurrent,getList,get,setCurrent,update,listKeys)
3         ,PGB
4         ,createPGB
5         ,Markup (Text, Paragraph, Link, Bold, Emph, Heading, Url, Underline, Strike, Pre)
6         ,Document
7         ,wikiParser
8         ,htmlOutput
9
10 ) where
11
12 import Dbconnect
13 import Data.Char
14 import Text.ParserCombinators.Parsec
15
16 class Backend a where
17         --Keyword -> (Full text,date)
18         getCurrent :: a -> String -> IO (Maybe (String,String))
19
20         --Keyword -> [(id,date,author,comment)]
21         getList :: a -> String -> IO [(String, String, String, String)]
22
23         --Keyword -> id -> Full text
24         get :: a -> String -> String -> IO (Maybe String)
25
26         --Keyword -> id -> ()
27         setCurrent :: a -> String -> String -> IO Bool
28
29         --Keyword -> Full text -> id
30         update :: a -> String -> String -> String -> String -> IO String
31
32         --[Keyword]
33         listKeys :: a -> IO [String]
34
35 data Markup = Text String
36         | Paragraph 
37         | Link String String
38         | Bold [Markup]
39         | Emph [Markup]
40         | Heading Int [Markup]
41         | Url String
42         | Underline [Markup]
43         | Strike [Markup]
44         | Pre String
45
46 type Document = [Markup]
47
48 wikiParser :: GenParser Char st Document        
49 wikiParser = many1 pMain
50
51 pPara = do
52         pEol
53         pEol
54         return (Paragraph)
55
56 pSpace = do
57         c <- space 
58         return (Text (c:[]))
59
60 pEol = char '\n' <|> do
61         char '\r'
62         char '\n'
63
64 pLinkParser = do try (string "]]" >> return ([],[])) 
65         <|> try (do
66                 string " | "
67                 d <- pString "]]"
68                 return ([],d))
69         <|> (do
70                 c <- anyChar
71                 (l,d) <- pLinkParser
72                 return (c:l,d))
73
74 pLink = do
75         string "[["
76         (l,d) <- pLinkParser
77         case d of
78                 [] -> return (Link l l)
79                 _ -> return (Link l d)
80
81 pBold = pS "**" (\s -> Bold s)
82 pEmph = pS "//" (\s -> Emph s)
83 pUnderline = pS "__" (\s -> Underline s)
84 pStrike = pS "--" (\s -> Strike s)
85
86 pS s f = do
87         string s
88         s <- pStopAt s
89         return (f s)
90
91 pStopAt xs = pUntil pMain xs
92 pString xs = pUntil anyChar xs
93 pUntil p xs = manyTill p (try $ string xs)
94         
95 pHeading = do
96         many1 pEol
97         level <- many1 $ char '='
98         char ' '
99         s <- pStopAt (' ':level)
100         return (Heading (length level) s)
101
102 pURL = do
103         proto <- many1 letter
104         string "://"
105         s <- many1 (alphaNum <|> oneOf "?.:&-/")
106         return (Url (proto++"://"++s))
107
108 pPre = do
109         string "<pre>"
110         s <- pString "</pre>"
111         return (Pre s)
112         
113 pMain = choice [
114         try (pHeading)
115         ,try (pPara) 
116         ,pSpace 
117         ,try(pPre) 
118         ,try(pBold) 
119         ,try(pEmph) 
120         ,try(pUnderline) 
121         ,try(pStrike) 
122         ,try (pLink)
123         ,try (pURL)
124         ,pOtherChar
125         ,pText
126         ]
127
128 pOtherChar = do
129         c <- oneOf "*,;.:!?[]()'\"=-%$£<>/\\|"
130         return (Text (c:[]))
131
132 pText = do
133         t <- many1 alphaNum
134         return (Text t)
135
136 newtype PGB = PGB DBService
137
138 createPGB :: String -> String -> String -> String -> IO PGB
139 createPGB host database user password = let db = createDBService host database "" user password Nothing in return (PGB db)
140
141 instance Backend PGB where
142
143         getCurrent (PGB db) key = do 
144                 result <- selectReturnTuples db $ "SELECT fulltext,timestamp FROM curtexts WHERE keyword="++tov key
145                 case result of
146                         [text,date]:_ -> return (Just (text,date))
147                         _ -> return Nothing
148
149         getList (PGB db) key = do
150                 list <- selectReturnTuples db $ "SELECT id, timestamp, author, comment from fulltexts WHERE keyword = "++tov key
151                 case list of
152                         [[]] -> return []
153                         _ -> return $ map (\[id,date,author,comment] -> (id,date,author,comment)) list
154
155         get (PGB db) key id = do
156                 list <- selectReturnTuples db $ "SELECT fulltext from fulltexts WHERE id = "++tov id    
157                 case list of
158                         [s]:_ -> return (Just s)
159                         _ -> return Nothing
160
161         setCurrent (PGB db) key id = do
162                 full <- selectReturnTuples db $ "SELECT keyword FROM fulltexts WHERE keyword="++tov key++" AND id='"++id++"'"
163                 cur <- selectReturnTuples db $ "SELECT keyword FROM curtexts WHERE keyword="++tov key
164                 case full of
165                         [[]] -> do
166                                 return False
167                         _  -> do
168                                 rows <- case cur of
169                                         [[]] -> do
170                                                 execute db $ "INSERT INTO current (keyword, id) VALUES ("++tov key++","++tov id++")"
171                                         _  -> do
172                                                 execute db $ "UPDATE current SET id = "++tov id++" WHERE keyword = "++tov key
173                                 if rows == 1 then return True
174                                         else return False 
175
176         update (PGB db) key text author comment = do
177                 rows <- execute db $ "INSERT INTO fulltexts (keyword,fulltext, author, comment) VALUES ("++tov key++","++tov text++","++tov author++","++tov comment++")"
178                 if rows == 0 then return ""
179                         else do
180                                 [[id]] <- selectReturnTuples db $ "SELECT currval('fulltexts_id_seq')" 
181                                 setCurrent (PGB db) key id
182                                 return id
183
184         listKeys (PGB db) = do
185                 list <- selectReturnTuples db $ "SELECT keyword FROM current keyword ORDER BY lower(keyword)"
186                 case list of
187                         [[]] -> return []
188                         _ -> mapM (\[key] -> return key) list
189                 
190                         
191
192 tov :: String -> String
193 tov s = '\'':escapeQuery s++"'"
194                 
195 toHtml :: [Markup] -> String
196 toHtml [] = []
197 toHtml ((Paragraph):xs) = "<p>\n"++toHtml xs
198 toHtml ((Text s):xs) = s++toHtml xs
199 toHtml ((Link l d):xs) = "<link: "++l++" desc: "++d++">"++toHtml xs
200 toHtml ((Bold d):xs) = "<b>"++toHtml d++"</b>"++toHtml xs
201 toHtml ((Emph d):xs) = "<em>"++toHtml d++"</em>"++toHtml xs
202 toHtml ((Underline d):xs) = "<u>"++toHtml d++"</u>"++toHtml xs
203 toHtml ((Strike d):xs) = "<strike>"++toHtml d++"</strike>"++toHtml xs
204 toHtml ((Heading n d):xs) = "\n<h"++show n++">"++toHtml d++"</h"++show n++">\n"++toHtml xs
205 toHtml ((Url l):xs) = "<link: "++l++">"++toHtml xs
206 toHtml ((Pre s):xs) = "<pre>"++s++"</pre>"++toHtml xs
207
208
209 htmlOutput s = case parse wikiParser "" s of
210                                         Right n -> do 
211                                                 putStr (toHtml n)
212                                         Left e -> do
213                                                 print e