mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-28 08:06:24 -07:00
Add basic geoip detection to posts, add image to post flag template
This commit is contained in:
parent
04d25a211f
commit
2007b90556
8 changed files with 86 additions and 14 deletions
|
@ -345,8 +345,8 @@ func (p *Post) Insert(bumpThread bool, boardID int, locked bool, stickied bool,
|
|||
}
|
||||
insertSQL := `INSERT INTO DBPREFIXposts
|
||||
(thread_id, is_top_post, ip, created_on, name, tripcode, is_role_signature, email, subject,
|
||||
message, message_raw, password)
|
||||
VALUES(?,?,PARAM_ATON,CURRENT_TIMESTAMP,?,?,?,?,?,?,?,?)`
|
||||
message, message_raw, password, flag, country)
|
||||
VALUES(?,?,PARAM_ATON,CURRENT_TIMESTAMP,?,?,?,?,?,?,?,?,?,?)`
|
||||
bumpSQL := `UPDATE DBPREFIXthreads SET last_bump = CURRENT_TIMESTAMP WHERE id = ?`
|
||||
|
||||
tx, err := BeginTx()
|
||||
|
@ -381,7 +381,7 @@ func (p *Post) Insert(bumpThread bool, boardID int, locked bool, stickied bool,
|
|||
}
|
||||
if _, err = stmt.Exec(
|
||||
p.ThreadID, p.IsTopPost, p.IP, p.Name, p.Tripcode, p.IsRoleSignature, p.Email, p.Subject,
|
||||
p.Message, p.MessageRaw, p.Password,
|
||||
p.Message, p.MessageRaw, p.Password, p.Flag, p.Country,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
package geoip
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidCountry = errors.New("unrecognized country abbreviation")
|
||||
)
|
||||
|
||||
var abbrMap = map[string]string{
|
||||
"af": "Afghanistan",
|
||||
"ax": "Aland Islands",
|
||||
|
@ -247,3 +256,11 @@ var abbrMap = map[string]string{
|
|||
"zm": "Zambia",
|
||||
"zw": "Zimbabwe",
|
||||
}
|
||||
|
||||
func GetCountryName(abbr string) (string, error) {
|
||||
title, ok := abbrMap[strings.ToLower(abbr)]
|
||||
if !ok {
|
||||
return "", ErrInvalidCountry
|
||||
}
|
||||
return title, nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -15,13 +18,21 @@ var (
|
|||
ErrUnrecognized = errors.New("unrecognized GeoIP handler ID")
|
||||
)
|
||||
|
||||
// Country represents the GeoIP data used by gochan (the country/flag name and
|
||||
// country abbreviation/flag filename, accessible in /static/flags/{flag}).
|
||||
type Country struct {
|
||||
Name string
|
||||
Flag string
|
||||
}
|
||||
|
||||
func (c *Country) IsGeoIP() bool {
|
||||
if _, ok := abbrMap[c.Flag]; ok {
|
||||
// IsGeoIP is true of the country has a recognized abbreviation set as its
|
||||
// flag. Otherwise it is assumed to be either a custom flag, or no flag if
|
||||
// the string is blank
|
||||
func (c Country) IsGeoIP() bool {
|
||||
if c.Flag == "" || c.Name == "" {
|
||||
return false
|
||||
}
|
||||
if _, err := GetCountryName(c.Flag); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -29,7 +40,7 @@ func (c *Country) IsGeoIP() bool {
|
|||
|
||||
type GeoIPHandler interface {
|
||||
Init(options map[string]any) error
|
||||
GetCountry(request *http.Request, board string) (*Country, error)
|
||||
GetCountry(request *http.Request, board string, errEv *zerolog.Event) (*Country, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
|
@ -60,11 +71,21 @@ func SetupGeoIP(id string, options map[string]any) (err error) {
|
|||
return activeHandler.Init(options)
|
||||
}
|
||||
|
||||
func LookupCountry(request *http.Request, board string) (*Country, error) {
|
||||
// GetCountry looks up the country the request comes from using the active handler.
|
||||
// It throws ErrNotConfigured if one has not been configured
|
||||
func GetCountry(request *http.Request, board string, errEv ...*zerolog.Event) (*Country, error) {
|
||||
if activeHandler == nil {
|
||||
return nil, ErrNotConfigured
|
||||
}
|
||||
return activeHandler.GetCountry(request, board)
|
||||
var ev *zerolog.Event
|
||||
if errEv != nil {
|
||||
ev = errEv[0]
|
||||
} else {
|
||||
ev = gcutil.LogError(nil).
|
||||
Str("ip", gcutil.GetRealIP(request))
|
||||
defer ev.Discard()
|
||||
}
|
||||
return activeHandler.GetCountry(request, board, ev)
|
||||
}
|
||||
|
||||
func Close() error {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/oschwald/maxminddb-golang"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -87,18 +88,23 @@ func (mh *mmdbHandler) Init(options map[string]any) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (mh *mmdbHandler) GetCountry(request *http.Request, board string) (*Country, error) {
|
||||
var err error
|
||||
func (mh *mmdbHandler) GetCountry(request *http.Request, board string, errEv *zerolog.Event) (*Country, error) {
|
||||
if mh.db == nil {
|
||||
return nil, err
|
||||
return nil, nil
|
||||
}
|
||||
errEv.Str("board", board)
|
||||
ip := net.ParseIP(gcutil.GetRealIP(request))
|
||||
if ip == nil {
|
||||
// this shouldn't happen unless something has gone very wrong
|
||||
errEv.Err(ErrInvalidIP).Caller().Caller(1).Send()
|
||||
return nil, ErrInvalidIP
|
||||
}
|
||||
var record mmdbRecord
|
||||
err = mh.db.Lookup(ip, &record)
|
||||
err := mh.db.Lookup(ip, &record)
|
||||
if err != nil {
|
||||
// thrown if something went wrong trying to unmarshal the database data, not
|
||||
// if the country couldn't be found from the IP
|
||||
errEv.Err(err).Caller().Caller(1).Send()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -106,8 +112,16 @@ func (mh *mmdbHandler) GetCountry(request *http.Request, board string) (*Country
|
|||
Flag: record.Country.ISOCode,
|
||||
}
|
||||
var ok bool
|
||||
if record.Country.Names == nil {
|
||||
// Country not found (possibly private IP)
|
||||
country.Flag = "unknown.png"
|
||||
country.Name = "Unknown Country"
|
||||
return country, nil
|
||||
}
|
||||
country.Name, ok = record.Country.Names[mh.isoCode]
|
||||
if !ok {
|
||||
errEv.Err(ErrInvalidISOCode).Caller().Caller(1).
|
||||
Str("isoCode", mh.isoCode).Send()
|
||||
return nil, ErrInvalidISOCode
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/gochan-org/gochan/pkg/events"
|
||||
"github.com/gochan-org/gochan/pkg/gcsql"
|
||||
"github.com/gochan-org/gochan/pkg/gcutil"
|
||||
"github.com/gochan-org/gochan/pkg/posting/geoip"
|
||||
"github.com/gochan-org/gochan/pkg/posting/uploads"
|
||||
"github.com/gochan-org/gochan/pkg/server"
|
||||
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
||||
|
@ -247,6 +248,17 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if boardConfig.EnableGeoIP {
|
||||
geoipInfo, err := geoip.GetCountry(request, postBoard.Dir, errEv)
|
||||
if err != nil {
|
||||
// GetCountry logs the error
|
||||
server.ServeError(writer, "Unable to get post info", wantsJSON, nil)
|
||||
return
|
||||
}
|
||||
post.Country = geoipInfo.Name
|
||||
post.Flag = strings.ToLower(geoipInfo.Flag)
|
||||
}
|
||||
|
||||
captchaSuccess, err := submitCaptchaResponse(request)
|
||||
if err != nil {
|
||||
server.ServeError(writer, "Error submitting captcha response:"+err.Error(), wantsJSON, nil)
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
<link id="theme" rel="stylesheet" href="{{webPath "/css/" .boardConfig.DefaultStyle}}" />
|
||||
{{- end}}
|
||||
<link rel="shortcut icon" href="{{webPath "/favicon.png"}}">
|
||||
{{- if .boardConfig.EnableGeoIP -}}
|
||||
<link id="flags" rel="stylesheet" href="{{webPath `/css/flags.css`}}"/>
|
||||
{{- end -}}
|
||||
<script type="text/javascript" src="{{webPath "/js/consts.js"}}"></script>
|
||||
<script type="text/javascript" src="{{webPath "/js/gochan.js"}}"></script>
|
||||
</head>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
{{- end -}}
|
||||
{{- if ne .post.Email ""}}</a>{{end}}</span>
|
||||
{{- if ne .post.Tripcode ""}}<span class="tripcode">!{{.post.Tripcode}}</span>{{end -}}
|
||||
{{- if ne .post.Country.Flag ""}}{{template "post_flag" .post}}{{end}} {{formatTimestamp .post.Timestamp -}}
|
||||
{{- if ne .post.Country.Flag ""}}{{template "post_flag" .post.Country}}{{end}} {{formatTimestamp .post.Timestamp -}}
|
||||
</label> <a href="{{.post.WebPath}}">No.</a> <a href="javascript:quote({{.post.ID}})" class="backlink-click">{{.post.ID}}</a>
|
||||
<span class="status-icons">
|
||||
{{- if $.thread.Locked -}}<img src="{{webPath "/static/lock.png"}}" class="locked-icon" alt="Thread locked" title="Thread locked">{{end -}}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
{{define "post_flag"}}
|
||||
<div class="flag-geoip flag-{{.Flag}}"></div>
|
||||
<img {{if .IsGeoIP -}}
|
||||
class="flag-geoip flag-{{.Flag}}"
|
||||
{{- else -}}
|
||||
class="flag-geoip" src="{{webPath `/static/flags/` .Flag}}"
|
||||
{{- end -}}
|
||||
title="{{.Name}}" />
|
||||
{{- end -}}
|
Loading…
Add table
Add a link
Reference in a new issue