packages feed

happs-tutorial-0.4.1: src/ControllerGetActions.hs

{-# LANGUAGE PatternSignatures, NoMonomorphismRestriction #-}
module ControllerGetActions where

import Control.Monad
import Control.Monad.Reader

import HAppS.Server

import ControllerMisc

import StateStuff
import ViewStuff
import Data.List
import qualified Data.Set as S

import Misc


-- This could be a lot less verbose, and use shorter variable names,
-- but it's the tutorial instructional example for using FromData to deal with forms, so no harm.
data JobsPaginationUrlData = JobsPaginationUrlData { jpCurrPage :: Int, jpResultsPerPage :: Int }
instance FromData JobsPaginationUrlData where
    fromData =
        let readerCurrpage,readerResultsPerPage :: ReaderT ([(String, Input)], [(String, Cookie)]) Maybe Int
            readerCurrpage = return . read -- convert string to int
                               =<< look "currentpage" `mplus` return "1" -- get string from urlencoded get string
            readerResultsPerPage = return . read =<< look "resultsPerPage" `mplus` return "10"               

            readerJobsPaginationUrlData :: ReaderT ([(String,Input)], [(String,Cookie)]) Maybe JobsPaginationUrlData
            readerJobsPaginationUrlData = liftM2 JobsPaginationUrlData readerCurrpage readerResultsPerPage
        in  readerJobsPaginationUrlData    


--viewJobs :: RenderGlobals -> Pagination -> [ServerPartT IO Response]
viewJobs rglobs  = withData $ \(JobsPaginationUrlData currP resPP) -> 
  [ ServerPartT $ \rq -> do 
  rsListAllJobs <- query ListAllJobs  
  let jobTable = paintAllJobsTable rglobs rsListAllJobs currP resPP
      -- if not logged in, you get invited to post a job,
      -- basically an incentive to register

      -- this next line should be coming from a template, and it's duplicated elsewhere, slightly bad.
      tmplattrs = maybe (def++[("postJob","post a HAppS job")]) (\_ -> def) (mbUser rglobs)
        where def = [("jobTable",  jobTable)]
  return . tutlayoutU rglobs tmplattrs $ "jobs"
  ]



data JobLookup = JobLookup {postedBy:: String, jobName :: String}
instance FromData JobLookup where
    fromData = liftM2 JobLookup (look "user")
                                (look "job")
viewJob rglobs  =
  withData $ \(JobLookup pBy jN) ->
    [ ServerPartT $ \rq -> do
        mbJ <- lookupJob pBy jN 
        case mbJ of
          Nothing -> return $ tutlayoutU rglobs [("errmsg", "no job found")] "errortemplate"
          Just j -> return $ tutlayoutU rglobs [("job",paintjob rglobs pBy j)] "viewjob"
     
    ]

lookupJob pBy jN = do
  appUsers <- query AskDatastore
  return $ do u <- find ( (==pBy) . username) . S.toList $ appUsers
              find ( (==jN) . jobname) $ jobs u



data UserNameUrlString = UserNameUrlString {profilename :: String}
instance FromData UserNameUrlString where
    fromData = liftM UserNameUrlString (look "user")

userProfile rglobs = 
  withData $ \(UserNameUrlString user) ->
    [ ServerPartT $ \rq -> do

        mbCP <- do mbU <- query (GetUser user)  
                   return $ do u <- mbU
                               return . consultantprofile $ u

        case mbCP of
          Nothing -> return $ tutlayoutU rglobs [("errormsgProfile", "bad user: " ++ user)] "viewconsultantprofile"
          Just cp  -> return . tutlayoutU rglobs [("cp",paintProfile rglobs user cp)] $ "viewconsultantprofile"
    ]



pageMyJobPosts rglobs = ServerPartT $ \rq -> do        
  let r = renderTemplateGroup (templates rglobs)
  case mbUser rglobs of
    Nothing -> return . tutlayoutU rglobs [("errormsg", "error: no user")] $ "errortemplate"
    Just currU -> do
          let jobPostsTable = paintUserJobsTable rglobs (username currU) (jobs currU) 1 20
          return $ tutlayoutU rglobs [("jobPostsTable",jobPostsTable)] "myjobposts"

-- viewEditJob :: RenderGlobals -> ServerPartT IO Response        
viewEditJobWD rglobs = withData $ \(JobLookup pBy jN) -> [viewEditJob pBy jN rglobs]
deleteJobWD rglobs = withData $ \(JobLookup pBy jN) -> [deleteJob pBy jN rglobs]

-- there's a lot of repeated code for viewEdit and Delete of jobs. 
-- maybe can consolidate
deleteJob pBy jN rglobs = ServerPartT $ \rq -> do        
    case mbUser rglobs of
      Nothing -> return $ tutlayoutU rglobs [("errormsg", "error: no user")] "errortemplate"
      Just currU@(User n p cp js) -> do
        if (username currU) /= pBy
           then return $ tutlayoutU rglobs [("errormsg", "error: " ++ jN ++ " not posted by " ++ (username currU) )]
                           "errortemplate"
           else do
             mbJ <- lookupJob pBy jN 
             case mbJ of
               Nothing -> return $ tutlayoutU rglobs
                            [ ( "errormsg", "error, bad job: " ++ (show $ (pBy,jN) ) ) ] "errortemplate"
               Just j -> do -- deleting a job by filtering a list seems wrong.
                            -- probably should have used a Set rather than a list.
                            -- but whatever, it works.
                            let newjobs = filter (not . (==jN) . jobname) js
                                newuser = User n p cp newjobs
                            updateUserSp rglobs newuser pageMyJobPosts rq

viewEditJob pBy jN rglobs = ServerPartT $ \_ -> do        
    case mbUser rglobs of
      Nothing -> return $ tutlayoutU rglobs [("errormsg", "error: no user")] "errortemplate"
      Just currU -> do
        if (username currU) /= pBy
           then return $ tutlayoutU rglobs [("errormsg", "error: " ++ jN ++ " not posted by " ++ (username currU) )]
                           "errortemplate"
           else do
             mbJ <- lookupJob pBy jN 
             case mbJ of
               Nothing -> return $ tutlayoutU rglobs
                            [ ( "errormsg", "error, bad job: " ++ (show $ (pBy,jN) ) ) ] "errortemplate"
               Just j -> do let -- use show below to properly escape quotes
                                attrs = [ ("oldJobname", show . jobname $ j)
                                        , ("newJobname", show . jobname $ j)
                                        , ("budget", show . jobbudget $ j)
                                        , ("jobblurb", show . jobblurb $ j)
                                        , ("showJob",paintjob rglobs pBy j)
                                      ]
                            return $ tutlayoutU rglobs attrs "editjob" 



viewEditConsultantProfile :: RenderGlobals -> ServerPartT IO Response        
viewEditConsultantProfile rglobs = ServerPartT $ \rq -> do        
  case mbUser rglobs of
    Nothing -> return . tutlayoutU rglobs [("errormsg", "error: no user")] $ "errortemplate"
    Just currU -> do
      let cp = consultantprofile currU 
      let showPr = paintProfile rglobs (username currU) cp 
          listAsConsultantChecked = if consultant cp
                                      then "checked"
                                      else ""
          -- use show below to properly escape quotes
          attrs = [ ("blurb", show . blurb $ cp)
                        -- , ("jobsPosted",jobsPosted)
                        , ("contact",show . contact $ cp)
                        , ("listAsConsultantChecked", listAsConsultantChecked)
                        , ("profile",showPr)
                      ]
      return $ tutlayoutU rglobs attrs "editconsultantprofile"