Reste à prévoir la pagination et la recherche
This commit is contained in:
46
blog.go
46
blog.go
@@ -6,6 +6,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
)
|
)
|
||||||
@@ -17,8 +18,9 @@ type Post struct {
|
|||||||
Title string
|
Title string
|
||||||
Author string
|
Author string
|
||||||
Date string
|
Date string
|
||||||
|
DateTime time.Time
|
||||||
HTML template.HTML
|
HTML template.HTML
|
||||||
ShortText string
|
ShortText template.HTML
|
||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,28 +46,25 @@ func (b *Blog) GetPost(Id string) (Post, bool) {
|
|||||||
return ret, false
|
return ret, false
|
||||||
}
|
}
|
||||||
func (p *Post) GenerateExcerpt() {
|
func (p *Post) GenerateExcerpt() {
|
||||||
fmt.Println("----", p.Title)
|
|
||||||
|
p.ShortText = ""
|
||||||
if len(p.HTML) > 0 {
|
if len(p.HTML) > 0 {
|
||||||
fmt.Println("Short text is html", p.HTML)
|
|
||||||
heading, err := p.GetFirstHeading(string(p.HTML))
|
heading, err := p.GetFirstHeading(string(p.HTML))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
paragraph, err := p.GetFirstParagraph(string(p.HTML))
|
paragraph, err := p.GetFirstParagraphs(string(p.HTML))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
if len(heading) > 0 {
|
if len(heading) > 0 {
|
||||||
log.Println("heading is:", heading)
|
p.ShortText += template.HTML(heading)
|
||||||
p.ShortText += heading
|
|
||||||
}
|
}
|
||||||
if len(paragraph) > 0 {
|
if len(paragraph) > 0 {
|
||||||
log.Println("paragraph is:", paragraph)
|
p.ShortText += template.HTML(paragraph)
|
||||||
p.ShortText += paragraph
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Short text is text", p.Text)
|
p.ShortText = template.HTML(p.Text)
|
||||||
p.ShortText = p.Text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -88,22 +87,31 @@ func (p *Post) GetFirstHeading(html string) (string, error) {
|
|||||||
|
|
||||||
return htmlContent, nil
|
return htmlContent, nil
|
||||||
}
|
}
|
||||||
func (p *Post) GetFirstParagraph(html string) (string, error) {
|
func (p *Post) GetFirstParagraphs(html string) (string, error) {
|
||||||
|
|
||||||
doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
|
doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
firstParagraph := doc.Find("p").First()
|
var htmlContent string
|
||||||
if firstParagraph.Length() == 0 {
|
var numberOfTextChars int
|
||||||
return "", fmt.Errorf("no paragraph found")
|
|
||||||
}
|
|
||||||
|
|
||||||
htmlContent, err := goquery.OuterHtml(firstParagraph)
|
// Eventuellement trouver un moyen de ne plus examiner le reste du document
|
||||||
if err != nil {
|
// si 200 caractères atteints
|
||||||
return "", err
|
doc.Find("p,div,h1,h2,h3,h4,h5").Each(func(i int, s *goquery.Selection) {
|
||||||
}
|
|
||||||
|
if numberOfTextChars < 200 {
|
||||||
|
|
||||||
|
numberOfTextChars += len(s.Text())
|
||||||
|
|
||||||
|
content, err := goquery.OuterHtml(s)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
htmlContent += content
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return htmlContent, nil
|
return htmlContent, nil
|
||||||
}
|
}
|
||||||
|
@@ -14,10 +14,15 @@ type MailBoxConfiguration struct {
|
|||||||
SSL string
|
SSL string
|
||||||
InBox string
|
InBox string
|
||||||
}
|
}
|
||||||
|
type ServiceConfiguration struct {
|
||||||
|
Address string
|
||||||
|
Port string
|
||||||
|
}
|
||||||
type BlogConfiguration struct {
|
type BlogConfiguration struct {
|
||||||
Title string
|
Title string
|
||||||
ShortName string
|
ShortName string
|
||||||
MailBox MailBoxConfiguration
|
MailBox MailBoxConfiguration
|
||||||
|
Service ServiceConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (configuration *BlogConfiguration) Prompt() error {
|
func (configuration *BlogConfiguration) Prompt() error {
|
||||||
@@ -31,7 +36,7 @@ func (configuration *BlogConfiguration) Prompt() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString(configuration.ShortName) {
|
if !regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString(configuration.ShortName) {
|
||||||
return fmt.Errorf("short same invalid")
|
return fmt.Errorf("short name invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -73,5 +78,15 @@ func (configuration *BlogConfiguration) Prompt() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configuration.Service.Address, err = prompt("Listen address", nil, "127.0.0.1", configuration.Service.Address, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration.Service.Port, err = prompt("Listen port", nil, "8080", configuration.Service.Port, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -3,14 +3,23 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<link rel="stylesheet" href="../styles.css">
|
||||||
<title>{{.BlogTitle}}</title>
|
<title>{{.BlogTitle}}</title>
|
||||||
</head>
|
</head>
|
||||||
<h1><a href="/proxy/8080/">{{.BlogTitle}}</a></h1>
|
<h1 class="blogtitle"><a href="/proxy/8080/">{{.BlogTitle}}</a></h1>
|
||||||
<body>
|
<body>
|
||||||
<h2>{{.Title}}</h2>
|
<article class="post">
|
||||||
<div>
|
<header class="postheader">
|
||||||
|
<h2 class="posttitle">{{.Title}}</h2>
|
||||||
|
<p class="postdate"><time datetime="{{.Date}}">{{.Date}}</Time></p>
|
||||||
|
</header>
|
||||||
|
<div class="postcontent">
|
||||||
|
{{ if .HTML }}
|
||||||
{{.HTML}}
|
{{.HTML}}
|
||||||
|
{{ else }}
|
||||||
|
{{.Text}}
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
</article>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@@ -4,36 +4,19 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<title>{{.Title}}</title>
|
<title>{{.Title}}</title>
|
||||||
<style>
|
<link rel="stylesheet" href="styles.css">
|
||||||
a:link {
|
|
||||||
color: black;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
a:visited {
|
|
||||||
color: black;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: orange;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1><a href="/proxy/8080/">{{.Title}}</a></h1>
|
<h1 class="blogtitle"><a href="/proxy/8080/">{{.Title}}</a></h1>
|
||||||
{{range .Posts}}
|
{{range .Posts}}
|
||||||
<article>
|
<article class="shortpost">
|
||||||
<h2><a href=/proxy/8080/post/{{ .Id }}>{{.Title}}</a></h2>
|
<header class="shortpostheader">
|
||||||
<address>
|
<h2 class="shortposttitle"><a href=/proxy/8080/post/{{ .Id }}>{{.Title}}</a></h2>
|
||||||
{{.Author}}
|
<p class="shortpostdate"><time datetime="{{.Date}}">{{.Date}}</Time></p>
|
||||||
</address>
|
</header>
|
||||||
<div>
|
<div>
|
||||||
<b>Extrait:</b>
|
<blockquote class="shortpostcontent">{{.ShortText}}</blockquote>
|
||||||
<blockquote>{{.ShortText}}</blockquote>
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
|
||||||
<p>Publié le:<time datetime="{{.Date}}">{{.Date}}</Time></p>
|
|
||||||
</footer>
|
|
||||||
</article>
|
</article>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</body>
|
</body>
|
||||||
|
59
html/styles.css
Normal file
59
html/styles.css
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
a:link {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: orange;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.blogtitle {
|
||||||
|
color: coral;
|
||||||
|
text-decoration:underline;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
.shortpost {
|
||||||
|
|
||||||
|
}
|
||||||
|
.shortpostheader {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
.shortposttitle {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.shortpostdate {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: smaller;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
.shortpostcontent {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
.post {
|
||||||
|
|
||||||
|
}
|
||||||
|
.postheader {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
.posttitle {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.postdate {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: smaller;
|
||||||
|
font-weight: lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
.postcontent {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
9
imap.go
9
imap.go
@@ -7,6 +7,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"mime"
|
"mime"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -69,12 +70,11 @@ func (mb *MailBox) Connect() error {
|
|||||||
log.Println("Error connnecting to", imapServer, ":", err)
|
log.Println("Error connnecting to", imapServer, ":", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Println("Connected")
|
|
||||||
err = mb.Client.Login(mb.User, mb.Password).Wait()
|
err = mb.Client.Login(mb.User, mb.Password).Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("failed to login:", err)
|
log.Fatal("failed to login:", err)
|
||||||
}
|
}
|
||||||
log.Println("Logged in")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (mb *MailBox) ListFolders() ([]string, error) {
|
func (mb *MailBox) ListFolders() ([]string, error) {
|
||||||
@@ -122,6 +122,7 @@ func (mb *MailBox) GetMessages() ([]Post, error) {
|
|||||||
post.Author = messages[0].Envelope.To[0].Name
|
post.Author = messages[0].Envelope.To[0].Name
|
||||||
|
|
||||||
post.Date = messages[0].Envelope.Date.Format("2006/01/02 15:04")
|
post.Date = messages[0].Envelope.Date.Format("2006/01/02 15:04")
|
||||||
|
post.DateTime = messages[0].Envelope.Date
|
||||||
|
|
||||||
section := messages[0].FindBodySection(bodySection)
|
section := messages[0].FindBodySection(bodySection)
|
||||||
|
|
||||||
@@ -186,7 +187,6 @@ func (mb *MailBox) GetMessages() ([]Post, error) {
|
|||||||
post.HTML = template.HTML(buf.String())
|
post.HTML = template.HTML(buf.String())
|
||||||
post.GenerateExcerpt()
|
post.GenerateExcerpt()
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Println("Content-Type:", part.Header.Get("Content-Type"))
|
log.Println("Content-Type:", part.Header.Get("Content-Type"))
|
||||||
|
|
||||||
@@ -198,6 +198,9 @@ func (mb *MailBox) GetMessages() ([]Post, error) {
|
|||||||
}
|
}
|
||||||
posts = append(posts, post)
|
posts = append(posts, post)
|
||||||
}
|
}
|
||||||
|
sort.Slice(posts, func(i, j int) bool {
|
||||||
|
return posts[i].DateTime.After(posts[j].DateTime)
|
||||||
|
})
|
||||||
return posts, nil
|
return posts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
39
mailblog.go
39
mailblog.go
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed html/index.tmpl
|
//go:embed html/index.tmpl
|
||||||
@@ -14,6 +15,9 @@ var indexTemplate string
|
|||||||
//go:embed html/entry.tmpl
|
//go:embed html/entry.tmpl
|
||||||
var entryTemplate string
|
var entryTemplate string
|
||||||
|
|
||||||
|
//go:embed html/styles.css
|
||||||
|
var nativeCSS string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@@ -26,7 +30,6 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
configurationFileName := fmt.Sprintf("%s/.config/mailblog.json", home)
|
configurationFileName := fmt.Sprintf("%s/.config/mailblog.json", home)
|
||||||
log.Println("Mailblog starting using", configurationFileName)
|
|
||||||
|
|
||||||
file, err := os.Open(configurationFileName)
|
file, err := os.Open(configurationFileName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -60,24 +63,34 @@ func main() {
|
|||||||
blog.Lang = "fr-FR"
|
blog.Lang = "fr-FR"
|
||||||
blog.Title = configuration.Title
|
blog.Title = configuration.Title
|
||||||
go MailboxFetcher(configuration, &blog)
|
go MailboxFetcher(configuration, &blog)
|
||||||
StartServer(&blog)
|
StartServer(configuration, &blog)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MailboxFetcher(configuration BlogConfiguration, blog *Blog) {
|
func MailboxFetcher(configuration BlogConfiguration, blog *Blog) {
|
||||||
|
|
||||||
var mb MailBox
|
var mb MailBox
|
||||||
mb.Configure(&configuration.MailBox)
|
mb.Configure(&configuration.MailBox)
|
||||||
err := mb.Connect()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer mb.Close()
|
|
||||||
|
|
||||||
posts, err := mb.GetMessages()
|
for {
|
||||||
if err != nil {
|
err := mb.Connect()
|
||||||
log.Println(err)
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
posts, err := mb.GetMessages()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
mb.Close()
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mb.Close()
|
||||||
|
|
||||||
|
blog.mutex.Lock()
|
||||||
|
blog.Posts = posts
|
||||||
|
blog.mutex.Unlock()
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
|
||||||
}
|
}
|
||||||
blog.mutex.Lock()
|
|
||||||
defer blog.mutex.Unlock()
|
|
||||||
blog.Posts = posts
|
|
||||||
}
|
}
|
||||||
|
33
web.go
33
web.go
@@ -3,14 +3,17 @@ package main
|
|||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StartServer(blog *Blog) {
|
func StartServer(configuration BlogConfiguration, blog *Blog) {
|
||||||
|
|
||||||
|
mux := http.NewServeMux()
|
||||||
/* Handle home page (/): list of blog entries */
|
/* Handle home page (/): list of blog entries */
|
||||||
http.HandleFunc("GET /{$}",
|
mux.HandleFunc("GET /{$}",
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("%+v", r.Header)
|
||||||
tpl, err := template.New("index").Parse(indexTemplate)
|
tpl, err := template.New("index").Parse(indexTemplate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -24,7 +27,7 @@ func StartServer(blog *Blog) {
|
|||||||
|
|
||||||
})
|
})
|
||||||
/* Handle one post display(/post/{post ID}) */
|
/* Handle one post display(/post/{post ID}) */
|
||||||
http.HandleFunc("GET /post/{id}",
|
mux.HandleFunc("GET /post/{id}",
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
id := r.PathValue("id")
|
id := r.PathValue("id")
|
||||||
post, found := blog.GetPost(id)
|
post, found := blog.GetPost(id)
|
||||||
@@ -42,11 +45,31 @@ func StartServer(blog *Blog) {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
http.HandleFunc("GET /favicon.ico",
|
mux.HandleFunc("GET /styles.css",
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Add("Content-Type", "text/css")
|
||||||
|
w.Write([]byte(nativeCSS))
|
||||||
|
})
|
||||||
|
|
||||||
|
mux.HandleFunc("GET /favicon.ico",
|
||||||
func(w http.ResponseWriter, r *http.Request) {
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Println("favicon.ico")
|
log.Println("favicon.ico")
|
||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
http.ListenAndServe("0.0.0.0:8080", nil)
|
addr := net.JoinHostPort(configuration.Service.Address, configuration.Service.Port)
|
||||||
|
|
||||||
|
server := &http.Server{
|
||||||
|
Addr: addr,
|
||||||
|
Handler: mux,
|
||||||
|
}
|
||||||
|
|
||||||
|
server.ListenAndServe()
|
||||||
|
//http.ListenAndServe(addr, server)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
func isCodeServerProxy(r *http.Request) bool {
|
||||||
|
return len(r.Header.Get("code-server-session")) > 0
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Reference in New Issue
Block a user