Skip to content

Commit

Permalink
Add display of tasks as a html webpage
Browse files Browse the repository at this point in the history
  • Loading branch information
alufers committed Nov 24, 2023
1 parent 583055a commit 1264223
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 32 deletions.
3 changes: 2 additions & 1 deletion bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,13 @@ func main() {
phabricatorClient, err = gonduit.Dial(viper.GetString("phabricator.url"), &core.ClientOptions{
APIToken: viper.GetString("phabricator.token"),
Timeout: time.Second * 20,
// Client: client,
})
if err != nil {
log.Fatalf("Error connecting to phabricator, %s", err)
}

go runTaskServer()
runTaskServer()

telegramClient, err = tgbotapi.NewBotAPI(viper.GetString("telegram.token"))
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ module github.com/alufers/phabricatorTeleNotifier
go 1.19

require (
github.com/davecgh/go-spew v1.1.1
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
github.com/gomarkdown/markdown v0.0.0-20231115200524-a660076da3fd
github.com/spf13/viper v1.13.0
github.com/uber/gonduit v0.13.0
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/gomarkdown/markdown v0.0.0-20231115200524-a660076da3fd h1:PppHBegd3uPZ3Y/Iax/2mlCFJm1w4Qf/zP1MdW4ju2o=
github.com/gomarkdown/markdown v0.0.0-20231115200524-a660076da3fd/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
Expand Down
23 changes: 23 additions & 0 deletions logging_transport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"fmt"
"net/http"
"net/http/httputil"
)

type loggingTransport struct{}

func (s *loggingTransport) RoundTrip(r *http.Request) (*http.Response, error) {
bytes, _ := httputil.DumpRequestOut(r, true)

resp, err := http.DefaultTransport.RoundTrip(r)
// err is returned after dumping the response

respBytes, _ := httputil.DumpResponse(resp, true)
bytes = append(bytes, respBytes...)

fmt.Printf("%s\n", bytes)

return resp, err
}
172 changes: 146 additions & 26 deletions task_server.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
package main

import (
"bytes"
_ "embed"
"encoding/base64"
"encoding/json"
"fmt"
"html/template"
"io"
"log"
"net/http"
"regexp"
"sort"
"strings"

"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
"github.com/spf13/viper"
"github.com/uber/gonduit/requests"
)

Expand All @@ -29,13 +40,92 @@ var prioritiesSorted = []string{
"Normal",
"Low",
"Wishlist",
"*",
}

func mdToHTML(md string) string {
// create markdown parser with extensions
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
p := parser.NewWithExtensions(extensions)
doc := p.Parse([]byte(md))

// create HTML renderer with extensions
htmlFlags := html.CommonFlags | html.HrefTargetBlank
opts := html.RendererOptions{Flags: htmlFlags}
renderer := html.NewRenderer(opts)

return string(markdown.Render(doc, renderer))
}

func runTaskServer() {
mux := http.NewServeMux()

tpl := template.Must(template.New("tasks").Parse(tplData))
mux.HandleFunc("/get-phabri-file", func(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
infoReq := &GetFileInfoRequest{
ID: id,
}
var info GetFileInfoResp
err := phabricatorClient.Call("file.info", infoReq, &info)
if err != nil {
log.Printf("Error: %v", err)
fmt.Fprintf(w, "Error: %v", err)
return
}

///DDD
baseURL := viper.GetString("phabricator.url")
apiToken := viper.GetString("phabricator.token")

// Define the API endpoint and parameters
apiEndpoint := "/api/file.download"
phid := info.Phid

// Construct the full URL
fullURL := baseURL + apiEndpoint

// Prepare the request body
body := bytes.NewBufferString(fmt.Sprintf("api.token=%s&phid=%s", apiToken, phid))

// Make the HTTP POST request
response, err := http.Post(fullURL, "application/x-www-form-urlencoded", body)
if err != nil {
log.Printf("Error: %v", err)
fmt.Fprintf(w, "Error: %v", err)
return
}
defer response.Body.Close()

// Read the response body
responseBody, err := io.ReadAll(response.Body)
if err != nil {
log.Printf("Error: %v", err)
fmt.Fprintf(w, "Error: %v", err)
return
}

var download FileDownloadResp

err = json.Unmarshal(responseBody, &download)
if err != nil {
log.Printf("Error: %v", err)
fmt.Fprintf(w, "Error: %v", err)
return
}

////ENDDDD

data, err := base64.StdEncoding.DecodeString(download.Result)
if err != nil {
log.Printf("Error: %v", err)
fmt.Fprintf(w, "Error: %v", err)
return
}
w.Header().Set("Content-type", info.MimeType)
w.Write(data)

})
mux.HandleFunc("/phabri-tasks-for-dashboard", func(w http.ResponseWriter, r *http.Request) {
// query := r.URL.Query()
// if query.Get("token") != viper.GetString("server.token") {
Expand All @@ -55,11 +145,20 @@ func runTaskServer() {
return
}

tasksPreSorted := make([]PhabricatorTask, 0, len(tasks))
for _, v := range tasks {
tasksPreSorted = append(tasksPreSorted, v)
}
sort.Slice(tasksPreSorted, func(i, j int) bool {
return tasksPreSorted[i].ID > tasksPreSorted[j].ID
})

var tasksSorted []ExtendedPhabricatorTask

phids := make([]string, 0, len(tasks)*2)
for _, v := range tasks {
phids = append(phids, v.AuthorPHID)
phids = append(phids, v.ProjectPHIDs...)
}
phids = removeDuplicates(phids)
lookedUpPhids, err := phabricatorClient.PHIDLookup(requests.PHIDLookupRequest{
Expand All @@ -72,44 +171,65 @@ func runTaskServer() {
}

for _, priority := range prioritiesSorted {
for _, task := range tasks {
for _, task := range tasksPreSorted {
author, ok := lookedUpPhids[task.AuthorPHID]
authorName := ""
if ok {
authorName = author.FullName
}

if task.Priority == priority {
tasksSorted = append(tasksSorted, ExtendedPhabricatorTask{
PhabricatorTask: task,
AuthorName: authorName,
})
rendered := mdToHTML(task.Description)

// match tags like "{F602442}"
reg := regexp.MustCompile(`\{F\d+\}`)
rendered = reg.ReplaceAllStringFunc(rendered, func(s string) string {
s = strings.ReplaceAll(s, "{F", "")
s = strings.ReplaceAll(s, "}", "")
return fmt.Sprintf(`<img src="/get-phabri-file?id=%s" />`, s)
})

projectNames := make([]string, 0, len(task.ProjectPHIDs))
isImportant := false
for _, projectPHID := range task.ProjectPHIDs {
project, ok := lookedUpPhids[projectPHID]
if ok {
if project.FullName == "[SUBSKRYBCYJNY] Wszystkie taski" {
continue
}
if project.FullName == "Na monitor" {
isImportant = true
}
projectNames = append(projectNames, project.FullName)
}
}
}
}

// add all priority types that are not in the sorted list
for _, task := range tasks {
author, ok := lookedUpPhids[task.AuthorPHID]
authorName := ""
if ok {
authorName = author.FullName
}
found := false
for _, priority := range prioritiesSorted {
if task.Priority == priority {
found = true
break
if task.Priority == priority || priority == "*" {
// check if already added
found := false
for _, v := range tasksSorted {
if v.PhabricatorTask.Phid == task.Phid {
found = true
break
}
}
if !found {
tasksSorted = append(tasksSorted, ExtendedPhabricatorTask{
PhabricatorTask: task,
AuthorName: authorName,
RenderedDescription: template.HTML(rendered),
ProjectNames: projectNames,
IsImportant: isImportant,
})
}
}
}
if !found {
tasksSorted = append(tasksSorted, ExtendedPhabricatorTask{
PhabricatorTask: task,
AuthorName: authorName,
})
}
}

// move is important to the top
sort.SliceStable(tasksSorted, func(i, j int) bool {
return tasksSorted[i].IsImportant
})

// pretty print json
// b, _ := json.MarshalIndent(tasks, "", " ")
// fmt.Fprintf(w, "%s", b)
Expand Down
52 changes: 49 additions & 3 deletions tasks_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,49 @@
padding: 10px;
}

.task__project {
background-color: #ddd;
padding: 2px 5px;
border-radius: 3px;
font-size: 12px;
margin-right: 5px;
}

.task.important {
border-color: red;
border-width: 4px;
animation: blinker 3s linear infinite;
/* horizontal stripe */
background: linear-gradient(
90deg,
#fff 0px,
#ff000044 50px,
#fff 100px
);
background-position-x: -100px;
}
.task img {
max-height: 100px;
}
.task.important img {
max-height: 50vh;
}

@keyframes blinker {
0% {
border-color: red;
background-position-x: 0px;
}
50% {
border-color: transparent;
background-position-x: 100vw;
}
100% {
border-color: red;
background-position-x: 0px;
}
}


</style>
</head>
Expand All @@ -80,17 +123,20 @@
Tasks
</div>
{{range .}}
<div class="task">
<div class="task {{if .IsImportant}}important{{end}}">
<div class="task_header_row">
<div class="task__priority" style="background: {{.PriorityColor }};">{{ .Priority }}</div>
<div class="task__id">#{{.ID}}</div>

<div class="task__title">{{.Title}}</div>
{{range.ProjectNames}}
<div class="task__project">{{.}}</div>
{{end}}
<div class="task__author">Autor: {{.AuthorName}}</div>

</div>

<div class="task__description">{{.Description}}</div>
<div class="task__description">{{.RenderedDescription}}</div>
</div>
{{end}}

Expand All @@ -109,7 +155,7 @@
window.location.reload();

}
}, 1000 * 10);
}, 1000 * 60);
</script>
</body>
</html>
Loading

0 comments on commit 1264223

Please sign in to comment.