Skip to content

Commit

Permalink
Add News record
Browse files Browse the repository at this point in the history
  • Loading branch information
amitaibu committed Jul 23, 2024
1 parent 2069e34 commit 0469291
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 2 deletions.
59 changes: 59 additions & 0 deletions Application/Helper/Elasticsearch.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module Application.Helper.Elasticsearch where

import IHP.Prelude
import IHP.ModelSupport
import Database.Bloodhound
import Network.HTTP.Client
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Data.Aeson
import IHP.ControllerPrelude

import Generated.Types

-- Make News an instance of ToJSON to allow serialization
instance ToJSON News where
toJSON news = object
[ "id" .= (show news.id)
, "title" .= news.title
, "body" .= news.body
-- Add other fields as necessary
]

-- Initialize Elasticsearch connection
initES :: (?context :: ControllerContext) => IO BHEnv
initES = do
let server = ?context.frameworkConfig.esServer
manager <- newManager defaultManagerSettings
return $ mkBHEnv server manager

-- Index a news item in Elasticsearch
indexNews :: (?modelContext :: ModelContext, ?context :: ControllerContext) => News -> IO (Either BHError IndexResponse)
indexNews news = do
bhenv <- initES
let indexName = IndexName "news_index"
docId = DocId $ T.pack $ "news_" <> show news.id
runBH bhenv $ indexDocument indexName (MappingName "document") (toJSON news) docId

-- Search for news
searchNews :: (?modelContext :: ModelContext, ?context :: ControllerContext) => Text -> IO [SearchResult Value]
searchNews query = do
bhenv <- initES
let indexName = IndexName "news_index"
searchQuery = MultiMatchQuery ["title", "body"] (TE.encodeUtf8 query)
search = mkSearch (Just searchQuery) Nothing
result <- runBH bhenv $ searchByIndex indexName search
case result of
Left err -> do
putStrLn $ "Error: " ++ show err
return []
Right searchResult -> return $ hits $ searchHits searchResult

-- Helper function to use in your controllers
searchNewsHandler :: (?modelContext :: ModelContext, ?context :: ControllerContext) => Text -> IO [News]
searchNewsHandler query = do
results <- searchNews query
return $ mapMaybe (decode . encode . sourceAsJSON) results
5 changes: 3 additions & 2 deletions Application/Schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ BEGIN
END;
$$ language plpgsql;
-- Your database schema. Use the Schema Designer at http://localhost:8001/ to add some tables.

CREATE TABLE users (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
email TEXT NOT NULL,
password_hash TEXT NOT NULL,
locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,
failed_login_attempts INT DEFAULT 0 NOT NULL
);

CREATE TABLE landing_pages (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
Expand All @@ -40,6 +38,9 @@ CREATE TABLE paragraph_ctas (
);
CREATE INDEX paragraph_quotes_landing_page_id_index ON paragraph_quotes (landing_page_id);
CREATE INDEX paragraph_ctas_landing_page_id_index ON paragraph_ctas (landing_page_id);
CREATE TABLE news (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL
);
ALTER TABLE paragraph_ctas ADD CONSTRAINT paragraph_ctas_ref_landing_page_id FOREIGN KEY (landing_page_id) REFERENCES landing_pages (id) ON DELETE NO ACTION;
ALTER TABLE paragraph_ctas ADD CONSTRAINT paragraph_ctas_ref_ref_landing_page_id FOREIGN KEY (ref_landing_page_id) REFERENCES landing_pages (id) ON DELETE NO ACTION;
ALTER TABLE paragraph_quotes ADD CONSTRAINT paragraph_quotes_ref_landing_page_id FOREIGN KEY (landing_page_id) REFERENCES landing_pages (id) ON DELETE NO ACTION;
55 changes: 55 additions & 0 deletions Web/Controller/News.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module Web.Controller.News where

import Web.Controller.Prelude
import Web.View.News.Index
import Web.View.News.New
import Web.View.News.Edit
import Web.View.News.Show

instance Controller NewsController where
action NewsAction = do
news <- query @News |> fetch
render IndexView { .. }

action NewNewsAction = do
let news = newRecord
render NewView { .. }

action ShowNewsAction { newsId } = do
news <- fetch newsId
render ShowView { .. }

action EditNewsAction { newsId } = do
news <- fetch newsId
render EditView { .. }

action UpdateNewsAction { newsId } = do
news <- fetch newsId
news
|> buildNews
|> ifValid \case
Left news -> render EditView { .. }
Right news -> do
news <- news |> updateRecord
setSuccessMessage "News updated"
redirectTo EditNewsAction { .. }

action CreateNewsAction = do
let news = newRecord @News
news
|> buildNews
|> ifValid \case
Left news -> render NewView { .. }
Right news -> do
news <- news |> createRecord
setSuccessMessage "News created"
redirectTo NewsAction

action DeleteNewsAction { newsId } = do
news <- fetch newsId
deleteRecord news
setSuccessMessage "News deleted"
redirectTo NewsAction

buildNews news = news
|> fill @'[]
2 changes: 2 additions & 0 deletions Web/FrontController.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Web.View.Layout (defaultLayout)


-- Controller Imports
import Web.Controller.News
import Web.Controller.StyleGuide
import Web.Controller.Users
import Web.Controller.ImageStyle
Expand All @@ -20,6 +21,7 @@ instance FrontController WebApplication where
controllers =
[ startPage LandingPagesAction
-- Generator Marker
, parseRoute @NewsController
, parseRoute @StyleGuideController
, parseRoute @UsersController
, parseRoute @ImageStyleController
Expand Down
3 changes: 3 additions & 0 deletions Web/Routes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ instance AutoRoute UsersController

instance AutoRoute StyleGuideController


instance AutoRoute NewsController

10 changes: 10 additions & 0 deletions Web/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,13 @@ data UsersController
data StyleGuideController
= StyleGuideAction
deriving (Eq, Show, Data)

data NewsController
= NewsAction
| NewNewsAction
| ShowNewsAction { newsId :: !(Id News) }
| CreateNewsAction
| EditNewsAction { newsId :: !(Id News) }
| UpdateNewsAction { newsId :: !(Id News) }
| DeleteNewsAction { newsId :: !(Id News) }
deriving (Eq, Show, Data)
23 changes: 23 additions & 0 deletions Web/View/News/Edit.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Web.View.News.Edit where
import Web.View.Prelude

data EditView = EditView { news :: News }

instance View EditView where
html EditView { .. } = [hsx|
{breadcrumb}
<h1>Edit News</h1>
{renderForm news}
|]
where
breadcrumb = renderBreadcrumb
[ breadcrumbLink "News" NewsAction
, breadcrumbText "Edit News"
]

renderForm :: News -> Html
renderForm news = formFor news [hsx|

{submitButton}

|]
39 changes: 39 additions & 0 deletions Web/View/News/Index.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module Web.View.News.Index where
import Web.View.Prelude

data IndexView = IndexView { news :: [News] }

instance View IndexView where
html IndexView { .. } = [hsx|
{breadcrumb}

<h1>Index<a href={pathTo NewNewsAction} class="btn btn-primary ms-4">+ New</a></h1>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>News</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>{forEach news renderNews}</tbody>
</table>

</div>
|]
where
breadcrumb = renderBreadcrumb
[ breadcrumbLink "News" NewsAction
]

renderNews :: News -> Html
renderNews news = [hsx|
<tr>
<td>{news}</td>
<td><a href={ShowNewsAction news.id}>Show</a></td>
<td><a href={EditNewsAction news.id} class="text-muted">Edit</a></td>
<td><a href={DeleteNewsAction news.id} class="js-delete text-muted">Delete</a></td>
</tr>
|]
23 changes: 23 additions & 0 deletions Web/View/News/New.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Web.View.News.New where
import Web.View.Prelude

data NewView = NewView { news :: News }

instance View NewView where
html NewView { .. } = [hsx|
{breadcrumb}
<h1>New News</h1>
{renderForm news}
|]
where
breadcrumb = renderBreadcrumb
[ breadcrumbLink "News" NewsAction
, breadcrumbText "New News"
]

renderForm :: News -> Html
renderForm news = formFor news [hsx|

{submitButton}

|]
17 changes: 17 additions & 0 deletions Web/View/News/Show.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Web.View.News.Show where
import Web.View.Prelude

data ShowView = ShowView { news :: News }

instance View ShowView where
html ShowView { .. } = [hsx|
{breadcrumb}
<h1>Show News</h1>
<p>{news}</p>

|]
where
breadcrumb = renderBreadcrumb
[ breadcrumbLink "News" NewsAction
, breadcrumbText "Show News"
]

0 comments on commit 0469291

Please sign in to comment.