various changes
This commit is contained in:
parent
5f97675216
commit
79d73d12f5
12 changed files with 163 additions and 77 deletions
BIN
assets/favicon.ico
Normal file
BIN
assets/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 132 B |
|
|
@ -16,22 +16,6 @@ body {
|
||||||
background-color: lightgreen;
|
background-color: lightgreen;
|
||||||
padding: 0.5em 1em;
|
padding: 0.5em 1em;
|
||||||
color: darkgreen;
|
color: darkgreen;
|
||||||
animation: 500ms ease-out 3s 1 forwards fadeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeout {
|
|
||||||
0% {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
99% {
|
|
||||||
opacity: 0;
|
|
||||||
font-size: inherit;
|
|
||||||
height: inherit;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
font-size: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cols {
|
.cols {
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -5,7 +5,6 @@ go 1.16
|
||||||
require (
|
require (
|
||||||
github.com/fogleman/gg v1.3.0
|
github.com/fogleman/gg v1.3.0
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
github.com/gorilla/feeds v1.1.1
|
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/gorilla/sessions v1.2.1
|
github.com/gorilla/sessions v1.2.1
|
||||||
github.com/kr/pretty v0.3.0 // indirect
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,14 @@ var TplCommonMap = map[string]string{
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>status.cafe</title>
|
<title>{{ template "title" . }}Status Cafe</title>
|
||||||
<meta name="description" content="your friends' updates">
|
<meta name="description" content="your friends' updates">
|
||||||
<link rel="stylesheet" href="/assets/style.css"/>
|
<link rel="stylesheet" href="/assets/style.css"/>
|
||||||
|
{{ if .face }}
|
||||||
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>{{ .face }}</text></svg>">
|
||||||
|
{{ else }}
|
||||||
|
<link rel="icon" href="/assets/favicon.ico">
|
||||||
|
{{ end }}
|
||||||
{{ template "head" . }}
|
{{ template "head" . }}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -40,7 +45,7 @@ var TplCommonMap = map[string]string{
|
||||||
</html>
|
</html>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ define "head" }}{{ end }}
|
{{ define "head" }}{{ end }}
|
||||||
`,
|
{{ define "title" }}{{ end }}`,
|
||||||
"status": `{{ define "status" }}
|
"status": `{{ define "status" }}
|
||||||
<div class="status-username"><a href="/users/{{ .User }}">{{ .User }}</a> {{ .Face }} {{ .TimeAgo }}</div>
|
<div class="status-username"><a href="/users/{{ .User }}">{{ .User }}</a> {{ .Face }} {{ .TimeAgo }}</div>
|
||||||
<p class="status-content">{{ .Content }}</p>
|
<p class="status-content">{{ .Content }}</p>
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,112 @@ package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gorilla/feeds"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"status/model"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/xml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Feed struct {
|
||||||
|
XMLName xml.Name `xml:"http://www.w3.org/2005/Atom feed"`
|
||||||
|
Title string `xml:"title"`
|
||||||
|
ID string `xml:"id"`
|
||||||
|
Link []Link `xml:"link"`
|
||||||
|
Updated TimeStr `xml:"updated"`
|
||||||
|
Author *Person `xml:"author"`
|
||||||
|
Icon string `xml:"icon,omitempty"`
|
||||||
|
Logo string `xml:"logo,omitempty"`
|
||||||
|
Subtitle string `xml:"subtitle,omitempty"`
|
||||||
|
Entry []*Entry `xml:"entry"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Entry struct {
|
||||||
|
Title string `xml:"title"`
|
||||||
|
ID string `xml:"id"`
|
||||||
|
Link []Link `xml:"link"`
|
||||||
|
Published TimeStr `xml:"published"`
|
||||||
|
Updated TimeStr `xml:"updated"`
|
||||||
|
Author *Person `xml:"author"`
|
||||||
|
Summary *Text `xml:"summary"`
|
||||||
|
Content *Text `xml:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Link struct {
|
||||||
|
Rel string `xml:"rel,attr,omitempty"`
|
||||||
|
Href string `xml:"href,attr"`
|
||||||
|
Type string `xml:"type,attr,omitempty"`
|
||||||
|
HrefLang string `xml:"hreflang,attr,omitempty"`
|
||||||
|
Title string `xml:"title,attr,omitempty"`
|
||||||
|
Length uint `xml:"length,attr,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Name string `xml:"name"`
|
||||||
|
URI string `xml:"uri,omitempty"`
|
||||||
|
Email string `xml:"email,omitempty"`
|
||||||
|
InnerXML string `xml:",innerxml"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Text struct {
|
||||||
|
Type string `xml:"type,attr"`
|
||||||
|
Body string `xml:",chardata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimeStr string
|
||||||
|
|
||||||
|
func Time(t time.Time) TimeStr {
|
||||||
|
return TimeStr(t.Format("2006-01-02T15:04:05-07:00"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func createAtomEntryFromStatus(status model.Status) *Entry {
|
||||||
|
return &Entry{
|
||||||
|
Title: fmt.Sprintf("%s %s %s", status.User, status.Face, truncate(status.Content, 50)),
|
||||||
|
ID: fmt.Sprintf("https://status.cafe/users/%s/%d", status.User, status.Id),
|
||||||
|
//Link: []Link{
|
||||||
|
// {
|
||||||
|
// Rel: "alternate",
|
||||||
|
// Href: fmt.Sprintf("https://status.cafe/users/%s/%d", status.User, status.Id),
|
||||||
|
// Type: "text/html",
|
||||||
|
// },
|
||||||
|
//},
|
||||||
|
Updated: Time(status.CreatedAt),
|
||||||
|
Published: Time(status.CreatedAt),
|
||||||
|
Author: &Person{
|
||||||
|
Name: status.User,
|
||||||
|
URI: fmt.Sprintf("https://status.cafe/users/%s", status.User),
|
||||||
|
},
|
||||||
|
Content: &Text{
|
||||||
|
Type: "text",
|
||||||
|
Body: status.Content,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) showFeedView(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) showFeedView(w http.ResponseWriter, r *http.Request) {
|
||||||
now := time.Now()
|
feed := Feed{
|
||||||
feed := &feeds.Feed{
|
Title: "status.cafe",
|
||||||
Title: "status.cafe",
|
ID: "https://status.cafe/",
|
||||||
Link: &feeds.Link{Href: "https://status.cafe/"},
|
Subtitle: "Your friends' updates",
|
||||||
Author: &feeds.Author{Name: "status.cafe"},
|
Icon: "/assets/icon.png",
|
||||||
Created: now,
|
Author: &Person{
|
||||||
|
Name: "status.cafe",
|
||||||
|
URI: "https://status.cafe",
|
||||||
|
},
|
||||||
|
Updated: Time(time.Now()),
|
||||||
|
Link: []Link{
|
||||||
|
{
|
||||||
|
Rel: "self",
|
||||||
|
Href: "https://status.cafe/feed.atom",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Rel: "alternate",
|
||||||
|
Type: "text/html",
|
||||||
|
Href: "https://status.cafe",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
statuses, err := h.storage.StatusFeed()
|
statuses, err := h.storage.StatusFeed()
|
||||||
|
|
@ -23,25 +117,15 @@ func (h *Handler) showFeedView(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, status := range statuses {
|
for _, status := range statuses {
|
||||||
if err != nil {
|
feed.Entry = append(feed.Entry, createAtomEntryFromStatus(status))
|
||||||
serverError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
feed.Items = append(feed.Items, &feeds.Item{
|
|
||||||
Title: fmt.Sprintf("%s %s %s", status.User, status.Face, truncate(status.Content, 50)),
|
|
||||||
Link: &feeds.Link{Href: fmt.Sprintf("https://status.cafe/users/%s/%d", status.User, status.Id)},
|
|
||||||
Author: &feeds.Author{Name: status.User},
|
|
||||||
Content: status.Content,
|
|
||||||
Created: status.CreatedAt,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
atom, err := feed.ToAtom()
|
|
||||||
if err != nil {
|
|
||||||
serverError(w, err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
w.Header().Set("Content-Type", "application/atom+xml")
|
w.Header().Set("Content-Type", "application/atom+xml")
|
||||||
w.Write([]byte(atom))
|
var data []byte
|
||||||
|
data, err = xml.MarshalIndent(&feed, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
serverError(w, err)
|
||||||
|
}
|
||||||
|
w.Write([]byte(xml.Header + string(data)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,6 @@ var TplMap = map[string]string{
|
||||||
{{ if .form.Error }}
|
{{ if .form.Error }}
|
||||||
<p>{{ .form.Error }}</p>
|
<p>{{ .form.Error }}</p>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ template "flash" .flash }}
|
|
||||||
<form action="/add" method="post">{{ template "status_form" .status }}</form>
|
<form action="/add" method="post">{{ template "status_form" .status }}</form>
|
||||||
<ul class="tools">
|
<ul class="tools">
|
||||||
<li><a href="/about/status-updater">status updater</a> bookmarklet</li>
|
<li><a href="/about/status-updater">status updater</a> bookmarklet</li>
|
||||||
|
|
@ -369,7 +368,7 @@ var TplMap = map[string]string{
|
||||||
Drag the following link to your bookmarks toolbar:
|
Drag the following link to your bookmarks toolbar:
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=350,height=290'))">status updater</a>
|
<a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=350,height=350'))">status updater</a>
|
||||||
</p>
|
</p>
|
||||||
<p>That's it! From now on, whenever you want to update your status, click the status updater button from your bookmarks and a pop-up window will launch to let you update it.</p>
|
<p>That's it! From now on, whenever you want to update your status, click the status updater button from your bookmarks and a pop-up window will launch to let you update it.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -378,6 +377,8 @@ var TplMap = map[string]string{
|
||||||
<link rel="alternate" type="application/atom+xml" title="Atom feed" href="/users/{{ .user }}.atom" />
|
<link rel="alternate" type="application/atom+xml" title="Atom feed" href="/users/{{ .user }}.atom" />
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "title" }}{{ .user }} - {{ end }}
|
||||||
|
|
||||||
{{ define "content" }}
|
{{ define "content" }}
|
||||||
<div class="cols">
|
<div class="cols">
|
||||||
<section>
|
<section>
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,14 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>status.cafe</title>
|
<title>{{ template "title" . }}Status Cafe</title>
|
||||||
<meta name="description" content="your friends' updates">
|
<meta name="description" content="your friends' updates">
|
||||||
<link rel="stylesheet" href="/assets/style.css"/>
|
<link rel="stylesheet" href="/assets/style.css"/>
|
||||||
|
{{ if .face }}
|
||||||
|
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>{{ .face }}</text></svg>">
|
||||||
|
{{ else }}
|
||||||
|
<link rel="icon" href="/assets/favicon.ico">
|
||||||
|
{{ end }}
|
||||||
{{ template "head" . }}
|
{{ template "head" . }}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -30,3 +35,4 @@
|
||||||
</html>
|
</html>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ define "head" }}{{ end }}
|
{{ define "head" }}{{ end }}
|
||||||
|
{{ define "title" }}{{ end }}
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
{{ if .form.Error }}
|
{{ if .form.Error }}
|
||||||
<p>{{ .form.Error }}</p>
|
<p>{{ .form.Error }}</p>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ template "flash" .flash }}
|
|
||||||
<form action="/add" method="post">{{ template "status_form" .status }}</form>
|
<form action="/add" method="post">{{ template "status_form" .status }}</form>
|
||||||
<ul class="tools">
|
<ul class="tools">
|
||||||
<li><a href="/about/status-updater">status updater</a> bookmarklet</li>
|
<li><a href="/about/status-updater">status updater</a> bookmarklet</li>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
Drag the following link to your bookmarks toolbar:
|
Drag the following link to your bookmarks toolbar:
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=350,height=290'))">status updater</a>
|
<a href="javascript:void(open('https://status.cafe/add','status.cafe','resizable,scrollbars,width=350,height=350'))">status updater</a>
|
||||||
</p>
|
</p>
|
||||||
<p>That's it! From now on, whenever you want to update your status, click the status updater button from your bookmarks and a pop-up window will launch to let you update it.</p>
|
<p>That's it! From now on, whenever you want to update your status, click the status updater button from your bookmarks and a pop-up window will launch to let you update it.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
<link rel="alternate" type="application/atom+xml" title="Atom feed" href="/users/{{ .user }}.atom" />
|
<link rel="alternate" type="application/atom+xml" title="Atom feed" href="/users/{{ .user }}.atom" />
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "title" }}{{ .user }} - {{ end }}
|
||||||
|
|
||||||
{{ define "content" }}
|
{{ define "content" }}
|
||||||
<div class="cols">
|
<div class="cols">
|
||||||
<section>
|
<section>
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ func (h *Handler) initTpl() {
|
||||||
for name, content := range TplMap {
|
for name, content := range TplMap {
|
||||||
views[name] = template.Must(template.New("main").Funcs(template.FuncMap{
|
views[name] = template.Must(template.New("main").Funcs(template.FuncMap{
|
||||||
"faces": func() []string {
|
"faces": func() []string {
|
||||||
return []string{"🙂", "😎", "😛", "🥰", "👽", "😱", "🤔", "😯", "🤒", "😡", "🥺", "🥳", "🤖", "💀", "😴", "😭", "☕", "🍺", "📖", "🔥", "❄️", "✨", "💡", "🎼"}
|
return []string{"🙂", "😎", "😛", "🥰", "❤️", "👽", "😱", "🤔", "😯", "🤒", "😡", "🥺", "🥳", "🤖", "💀", "😴", "😭", "🤐", "🤢", "👀", "☕", "🍺", "📖", "🔥", "❄️", "✨", "💡", "🎶", "✈️", "🚄", "🍿", "📰", "✏️", "🍱", "🎄", "🎁", "🌧️", "🌙", "🎨", "📺", "🍕", "✅"}
|
||||||
}}).Parse(commonTemplates + content))
|
}}).Parse(commonTemplates + content))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/fogleman/gg"
|
"github.com/fogleman/gg"
|
||||||
"github.com/golang/freetype"
|
"github.com/golang/freetype"
|
||||||
"github.com/golang/freetype/truetype"
|
"github.com/golang/freetype/truetype"
|
||||||
"github.com/gorilla/feeds"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"golang.org/x/image/font"
|
"golang.org/x/image/font"
|
||||||
"golang.org/x/image/font/gofont/goregular"
|
"golang.org/x/image/font/gofont/goregular"
|
||||||
|
|
@ -75,9 +75,14 @@ func (h *Handler) showUserView(w http.ResponseWriter, r *http.Request) {
|
||||||
serverError(w, err)
|
serverError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
face := ""
|
||||||
|
if len(statuses) > 0 {
|
||||||
|
face = statuses[0].Face
|
||||||
|
}
|
||||||
h.renderLayout(w, "user", map[string]interface{}{
|
h.renderLayout(w, "user", map[string]interface{}{
|
||||||
"user": username,
|
"user": username,
|
||||||
"statuses": statuses,
|
"statuses": statuses,
|
||||||
|
"face": face,
|
||||||
"homepage": user.Homepage,
|
"homepage": user.Homepage,
|
||||||
"about": template.HTML(user.About),
|
"about": template.HTML(user.About),
|
||||||
"picture": user.Picture,
|
"picture": user.Picture,
|
||||||
|
|
@ -282,41 +287,42 @@ func (h *Handler) showAtomView(w http.ResponseWriter, r *http.Request) {
|
||||||
notFound(w)
|
notFound(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
feed := Feed{
|
||||||
now := time.Now()
|
Title: user.Name,
|
||||||
feed := &feeds.Feed{
|
ID: fmt.Sprintf("https://status.cafe/users/%s/", user.Name),
|
||||||
Title: user.Name,
|
Author: &Person{
|
||||||
Link: &feeds.Link{Href: fmt.Sprintf("https://status.cafe/users/%s", username)}, // TODO change the scheme?
|
Name: user.Name,
|
||||||
Author: &feeds.Author{Name: user.Name, Email: "todo@todo.com"}, // TODO EMAIL
|
URI: fmt.Sprintf("https://status.cafe/users/%s", user.Name),
|
||||||
Created: now,
|
},
|
||||||
|
Updated: Time(time.Now()),
|
||||||
|
Link: []Link{
|
||||||
|
{
|
||||||
|
Rel: "self",
|
||||||
|
Href: fmt.Sprintf("https://status.cafe/users/%s.atom", user.Name),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Rel: "alternate",
|
||||||
|
Href: fmt.Sprintf("https://status.cafe/users/%s", user.Name),
|
||||||
|
Type: "text/html",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Icon: user.Picture,
|
||||||
|
Logo: user.Picture,
|
||||||
}
|
}
|
||||||
|
|
||||||
statuses, _, err := h.storage.StatusByUsername(user.Name, 20, 0)
|
statuses, _, err := h.storage.StatusByUsername(user.Name, 20, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
serverError(w, err)
|
serverError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, status := range statuses {
|
for _, status := range statuses {
|
||||||
if err != nil {
|
feed.Entry = append(feed.Entry, createAtomEntryFromStatus(status))
|
||||||
serverError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
feed.Items = append(feed.Items, &feeds.Item{
|
|
||||||
Title: fmt.Sprintf("%s - %s", status.User, truncate(status.Content, 50)),
|
|
||||||
Link: &feeds.Link{Href: fmt.Sprintf("https://status.cafe/users/%s/%d", username, status.Id)},
|
|
||||||
Author: &feeds.Author{Name: user.Name},
|
|
||||||
Content: status.Content,
|
|
||||||
Created: status.CreatedAt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
atom, err := feed.ToAtom()
|
|
||||||
if err != nil {
|
|
||||||
serverError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
w.Header().Set("Content-Type", "application/atom+xml")
|
w.Header().Set("Content-Type", "application/atom+xml")
|
||||||
w.Write([]byte(atom))
|
var data []byte
|
||||||
|
data, err = xml.MarshalIndent(&feed, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
serverError(w, err)
|
||||||
|
}
|
||||||
|
w.Write([]byte(xml.Header + string(data)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue