blob: 687c16abc08ef2c6f179885846c295eaa29bc32d [file] [log] [blame]
Akrone2161562022-12-19 17:05:39 +01001package main
2
3import (
Akrona1f100a2023-03-07 11:03:01 +01004 "compress/gzip"
Akron3890fcc2022-12-20 15:26:36 +01005 "encoding/csv"
Akron65503a32023-01-02 12:38:32 +01006 "encoding/json"
Akron3890fcc2022-12-20 15:26:36 +01007 "io"
Akrone2161562022-12-19 17:05:39 +01008 "log"
9 "net/http"
Akron3890fcc2022-12-20 15:26:36 +010010 "os"
Akrona1f100a2023-03-07 11:03:01 +010011 "path/filepath"
Akrone2161562022-12-19 17:05:39 +010012
13 badger "github.com/dgraph-io/badger/v3"
Akron83b77a72023-03-17 13:37:06 +010014 ginI18n "github.com/gin-contrib/i18n"
Akrone2161562022-12-19 17:05:39 +010015 "github.com/gin-gonic/gin"
Akronce286af2022-12-28 13:58:26 +010016 "github.com/joho/godotenv"
Akron65503a32023-01-02 12:38:32 +010017 "github.com/mattn/go-jsonpointer"
Akron83b77a72023-03-17 13:37:06 +010018 "golang.org/x/text/language"
Akrone2161562022-12-19 17:05:39 +010019)
20
21var db *badger.DB
22
23func CheckSaleUrl(c *gin.Context) {
24
25 corpusID := c.Param("corpus_id")
26 docID := c.Param("doc_id")
27 textID := c.Param("text_id")
28
29 err := db.View(func(txn *badger.Txn) error {
30
31 item, err := txn.Get([]byte(corpusID + "/" + docID + "/" + textID))
32
33 if err != nil {
34 c.String(http.StatusNotFound, "No entry found")
Akron906a2c52022-12-21 11:35:28 +010035 return nil
Akrone2161562022-12-19 17:05:39 +010036 }
37
38 err = item.Value(func(v []byte) error {
39 c.String(http.StatusOK, string(v))
40 return nil
41 })
42
43 if err != nil {
Akronce5186d2022-12-21 11:15:50 +010044 return err
Akrone2161562022-12-19 17:05:39 +010045 }
46
47 return nil
48 })
49
50 if err != nil {
51 c.String(http.StatusNotFound, err.Error())
52 }
Akrone2161562022-12-19 17:05:39 +010053}
54
Akrona1f100a2023-03-07 11:03:01 +010055func add(dbx *badger.DB, corpusID, docID, textID string, provider string, url string) error {
56 err := dbx.Update(func(txn *badger.Txn) error {
Akron6aee7fe2022-12-20 16:00:54 +010057 err := txn.Set([]byte(corpusID+"/"+docID+"/"+textID), []byte(provider+","+url))
Akrone2161562022-12-19 17:05:39 +010058 return err
59 })
60 return err
61}
62
Akrona1f100a2023-03-07 11:03:01 +010063func InitDB(dir string) {
Akrone2161562022-12-19 17:05:39 +010064 if db != nil {
65 return
66 }
Akrona1f100a2023-03-07 11:03:01 +010067 db = initDB(dir)
68}
69
70func initDB(dir string) *badger.DB {
71 dbx, err := badger.Open(badger.DefaultOptions(dir))
Akrone2161562022-12-19 17:05:39 +010072 if err != nil {
73 log.Fatal(err)
74 }
Akrona1f100a2023-03-07 11:03:01 +010075 return dbx
Akrone2161562022-12-19 17:05:39 +010076}
77
78func closeDB() {
79 db.Close()
80}
81
Akrona1f100a2023-03-07 11:03:01 +010082func IndexDB(ri io.Reader) error {
83 return indexDB(ri, db)
84}
85
86// indexDB reads in a csv file and adds
87// information to the database
88func indexDB(ri io.Reader, dbx *badger.DB) error {
89
90 r := csv.NewReader(ri)
91
92 txn := dbx.NewTransaction(true)
93
94 i := 0
95
96 for {
97 record, err := r.Read()
98 if err == io.EOF {
99 break
100 }
101 if err != nil {
102 log.Fatal(err)
103 }
104
105 if err := txn.Set([]byte(record[0]), []byte(record[1]+","+record[2])); err == badger.ErrTxnTooBig {
106 log.Println("Commit", record[0], "after", i, "inserts")
107 i = 0
108 err = txn.Commit()
109 if err != nil {
110 log.Fatal("Unable to commit")
111 }
112 txn = db.NewTransaction(true)
113 _ = txn.Set([]byte(record[0]), []byte(record[1]+","+record[2]))
114 }
115 i++
116 }
117 return txn.Commit()
118}
119
Akrone2161562022-12-19 17:05:39 +0100120func setupRouter() *gin.Engine {
Akron83b77a72023-03-17 13:37:06 +0100121 gin.SetMode(gin.ReleaseMode)
122
Akrone2161562022-12-19 17:05:39 +0100123 r := gin.Default()
Akron83b77a72023-03-17 13:37:06 +0100124
125 // apply i18n middleware
126 r.Use(ginI18n.Localize(ginI18n.WithBundle(&ginI18n.BundleCfg{
127 RootPath: "./i18n",
128 AcceptLanguage: []language.Tag{language.German, language.English},
129 DefaultLanguage: language.English,
130 UnmarshalFunc: json.Unmarshal,
131 FormatBundleFile: "json",
132 })))
133
Akron5e1252e2022-12-19 17:57:56 +0100134 r.LoadHTMLGlob("templates/*")
135
Akronce286af2022-12-28 13:58:26 +0100136 korapServer := os.Getenv("KORAP_SERVER")
137 if korapServer == "" {
138 korapServer = "https://korap.ids-mannheim.de"
139 }
140
Akron65503a32023-01-02 12:38:32 +0100141 var pluginManifest map[string]any
142 json.Unmarshal([]byte(`{
Akronde331792023-01-10 11:36:15 +0100143 "name" : "External Resources",
144 "desc" : "Retrieve content from an external provider",
Akron65503a32023-01-02 12:38:32 +0100145 "embed" : [{
146 "panel" : "match",
147 "title" : "Full Text",
148 "classes" : ["plugin", "cart"],
149 "icon" : "\f07a",
150 "onClick" : {
151 "action" : "addWidget",
152 "template":"",
153 "permissions": [
154 "scripts",
155 "popups"
156 ]
157 }
158 }]
159 }`), &pluginManifest)
160
Akronde331792023-01-10 11:36:15 +0100161 externalResources := os.Getenv("KORAP_EXTERNAL_RESOURCES")
162 if externalResources == "" {
163 externalResources = "https://korap.ids-mannheim.de/plugin/external/"
Akron65503a32023-01-02 12:38:32 +0100164 }
Akronde331792023-01-10 11:36:15 +0100165 jsonpointer.Set(pluginManifest, "/embed/0/onClick/template", externalResources)
Akron65503a32023-01-02 12:38:32 +0100166
Akron79d83482023-01-02 10:53:24 +0100167 r.Use(func() gin.HandlerFunc {
168 return func(c *gin.Context) {
169 h := c.Writer.Header()
170 h.Set("Access-Control-Allow-Origin", "null")
171 h.Set("Access-Control-Allow-Credentials", "null")
172 h.Set("Vary", "Origin")
173 }
174 }(),
175 )
176
Akron60e11602023-01-02 11:16:43 +0100177 // Return widget page
Akron6aee7fe2022-12-20 16:00:54 +0100178 r.GET("/", func(c *gin.Context) {
Akron5e1252e2022-12-19 17:57:56 +0100179 c.HTML(http.StatusOK, "main.html", gin.H{
Akron83b77a72023-03-17 13:37:06 +0100180 "korapServer": korapServer,
181 "title": ginI18n.MustGetMessage("fulltext"),
182 "noAccess": ginI18n.MustGetMessage("noAccess"),
183 "fromProvider": ginI18n.MustGetMessage("fromProvider"),
Akron5e1252e2022-12-19 17:57:56 +0100184 })
185 })
186
Akronde331792023-01-10 11:36:15 +0100187 // Return resource information
Akronce5186d2022-12-21 11:15:50 +0100188 r.HEAD("/:corpus_id/:doc_id/:text_id", CheckSaleUrl)
Akrone2161562022-12-19 17:05:39 +0100189 r.GET("/:corpus_id/:doc_id/:text_id", CheckSaleUrl)
Akron60e11602023-01-02 11:16:43 +0100190
191 // Return plugin manifest
Akron65503a32023-01-02 12:38:32 +0100192 r.GET("/plugin.json", func(c *gin.Context) {
193 c.JSON(200, pluginManifest)
194 })
195
Akrone2161562022-12-19 17:05:39 +0100196 return r
197}
198
199func main() {
Akron3c58d0d2023-01-02 13:35:41 +0100200 if godotenv.Load() != nil {
201 log.Println(".env file not loaded.")
202 }
Akronce286af2022-12-28 13:58:26 +0100203
Akrona1f100a2023-03-07 11:03:01 +0100204 InitDB("db")
Akron3890fcc2022-12-20 15:26:36 +0100205 defer closeDB()
206
207 // Index csv file
208 if len(os.Args) > 1 {
209
210 file, err := os.Open(os.Args[1])
211 if err != nil {
212 log.Fatal(err)
213 }
Akron3890fcc2022-12-20 15:26:36 +0100214
Akrona1f100a2023-03-07 11:03:01 +0100215 fileExt := filepath.Ext(os.Args[1])
Akron3890fcc2022-12-20 15:26:36 +0100216
Akrona1f100a2023-03-07 11:03:01 +0100217 if fileExt == ".gz" || fileExt == ".csvz" {
218 var gzipr io.Reader
219 gzipr, err = gzip.NewReader(file)
Akron3890fcc2022-12-20 15:26:36 +0100220 if err != nil {
Akrona1f100a2023-03-07 11:03:01 +0100221 log.Fatal("Unable to open gzip file")
222 } else {
223 err = IndexDB(gzipr)
Akron3890fcc2022-12-20 15:26:36 +0100224 }
Akrona1f100a2023-03-07 11:03:01 +0100225 } else {
226 err = IndexDB(file)
Akron3890fcc2022-12-20 15:26:36 +0100227 }
Akron3890fcc2022-12-20 15:26:36 +0100228
229 if err != nil {
230 log.Fatal("Unable to commit")
231 }
Akron3890fcc2022-12-20 15:26:36 +0100232 }
Akron83b77a72023-03-17 13:37:06 +0100233
Akrone2161562022-12-19 17:05:39 +0100234 r := setupRouter()
Akronce286af2022-12-28 13:58:26 +0100235
Akronde331792023-01-10 11:36:15 +0100236 port := os.Getenv("KORAP_EXTERNAL_RESOURCES_PORT")
Akronce286af2022-12-28 13:58:26 +0100237 if port == "" {
238 port = "5722"
239 }
240
241 log.Fatal(http.ListenAndServe(":"+port, r))
Akrone2161562022-12-19 17:05:39 +0100242}