How to publish Table content on confluence wiki - rest

I have some data which is in table format (generated using Go https://github.com/olekukonko/tablewriter) API, I am trying to print the table content as it is on the confluence wiki from the rest API. But while passing it to the body Its format got disturbed and not able to print the table. Please suggest how to do the same for this use case.
Output:
+------------+------------+-------------------+ | name | sample | sample2 | +------------+------------+-------------------+ | test-1 | 20 | 1 | | test_4 | 20 | 1 | +------------+------------+-------------------+
**data**:
+------------+------------+-------------------+
| Name | sample | sample2 |
+------------+------------+-------------------+
| test-1 | 20 | 1 |
| test_4 | 20 | 1 |
+------------+------------+-------------------+
type Payload struct {
Type string `json:"type"`
Title string `json:"title"`
Space Space `json:"space"`
Version Version `json:"version"`
Body Body `json:"Body"`
}
type Space struct {
Key string `json:"key"`
}
type Version struct {
Number int `json:"number"`
}
type Storage struct {
Value string `json:"value"`
Representation string `json:"representation"`
}
type Body struct {
Storage Storage `json:"storage"`
}
func UpdateWiki(data string) int {
Payload_data := Payload{
Type: "page", Title: "",
Space: Space{Key: ""},
Version: Version{Number: 4},
Body: Body{Storage{Value: data, Representation: "storage"}},
}
payloadBytes, err := json.Marshal(Payload_data)
if err != nil {
fmt.Println(err)
}
body := bytes.NewReader(payloadBytes)
req, err := http.NewRequest("PUT", "https://wiki.xyz.io/rest/api/content/xxxxx", body)
//fmt.Println(err)
dump, err := httputil.DumpRequest(req, true)
fmt.Printf("%s", dump)
if err != nil {
fmt.Println(err)
}
req.SetBasicAuth("", "")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
fmt.Println(resp)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
return resp.StatusCode
}

Related

How to avoid duplicate row while gorm AutoMigrate

I want to insert to database from CSV file using gorm AutoMigrate and while inserting I want to avoid duplicate entry. How Can I achieve this? Please check the attached code.
type User struct {
gorm.Model
ID int64 `csv:"_" db:"id"`
FirstName string `csv:"First name" db:"first_name"`
LastName string `csv:"Last name" db:"last_name"`
Emails string `csv:"Emails" db:"emails"`
}
func main() {
file, err := os.Open(os.Args[1])
defer file.Close()
users := []User{}
err = gocsv.Unmarshal(file, &users)
db, err := gorm.Open(postgres.Open("host=xxx.xx.x.x user=database password=password dbname=database port=5432 sslmode=disable"))
err = db.AutoMigrate(&User{})
if err != nil {
panic(err)
}
result := db.Create(users)
if result.Error != nil {
panic(result.Error)
}
}
Example: Consider the below data
FIrst name
Last name
Emails
First
Name
first#example.com
Second
Name
second#example.com
Third
Name
Forth
Name
first#example.com
If we pass the above data, the first 3 rows should insert into the database i.e. we have to avoid duplicate email entries to the database. Thanks.
Note: If the email is empty then the row should be inserted into the database.
You have to sanitize "users" after err = gocsv.Unmarshal(file, &users)
Somethink like
func sanytize(arr []User) []User {
users := []User{}
mail := []string{}
for _, a := range arr {
if !contains(mail, a.Emails){
users = append(users, a)
}
mail = append(mail, a.Emails)
}
return users
}
func contains(arr []string, str string) bool {
for _, a := range arr {
if a == str {
return true
}
}
return false
}
....
err = gocsv.Unmarshal(file, &users)
users = sanytize(users)

Convert Bson.M to a map[string]interface

I'm trying to convert the structure I'm decoding with my query to map[string]interface.
Here is my code:
var m map[string]interface
var result []Result
type Result struct {
Id ResultId `bson:"_id"`
Filename string `bson:"filename"`
}
type ResultId struct {
Host string `bson:"host"`
}
group := bson.D{{"$group", bson.D{{"_id", bson.D{{"host","$host"}}}, {"filename", bson.D{{"$last","$filename"}}}}}}
collection := client.Database("mongodb").Collection("Meta")
cursor, err := collection.Aggregate(ctx, mongo.Pipeline{group})
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}
defer cursor.Close(ctx)
if err = cursor.All(ctx, &results); err != nil {
fmt.Printf("cursor.All() error:", err)
return c.JSON(http.StatusInternalServerError, err)
}
for _, value := range results {
m = append(m,&bson.M{value.Id.Host:value.Filename})
}
But it does not return a map[string]interface and for information I use the go.mongodb.org package.
append only works on slices, (refer to effective go's section for more on append)
The way to add elements to a map, is simply:
m["key"] = value
Also keep in mind maps need to be initialised which I don't see in your code. Either with make or by giving an initial value (can be an empty value)

Firestore - Retrieve posts for accounts a user follows

I am trying to retrieve posts from a list of accounts that a user follows, but am unsure on the best way to do so? I have implemented a the same structure from this stack overflow answer, as I found it sensible for what I was trying to create (see below).
Firestore-root
|
--- users (collection)
| |
| --- uid (documents)
| |
| --- name: "User Name"
| |
| --- email: "email#email.com"
|
--- following (collection)
| |
| --- uid (document)
| |
| --- userFollowing (collection)
| |
| --- uid (documents)
| |
| --- uid (documents)
|
--- posts (collection)
|
--- uid (documents)
|
--- userPosts (collection)
|
--- postId (documents)
| |
| --- title: "Post Title"
| |
| --- date: September 03, 2018 at 6:16:58 PM UTC+3
|
--- postId (documents)
|
--- title: "Post Title"
|
--- date: September 03, 2018 at 6:16:58 PM UTC+3
However, I am struggling to understand the best way to retrieve a list of posts where its document UID is the same as the one a user is following.
I have attempted to get all the users followers and then for each document, loop over it using another get, but haven't found a successful solution. An example of this code can be seen below:
var userFollowingList = [User]()
db.collection("Following").document(currentUserUID).collection("userFollowing")
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
completion(false)
} else {
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
userFollowingList = querySnapshot!.documents.compactMap { querySnapshot -> User? in
return try? querySnapshot.data(as: User.self)
}
}
for user in userFollowingList {
db.collection("Posts")
.getDocuments() { (tripQuerySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
completion(false)
} else {
for document in tripQuerySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
self.followingTrips = querySnapshot!.documents.compactMap { querySnapshot -> Trip? in
return try? querySnapshot.data(as: Trip.self)
}
}
}
}
}
}
What is the most efficient way to achieve this? Thanks.
30/03/2020 UPDATE:
I ended up looping over each userID in the following list and returning all the posts for the users, but I'm still not sure if this is the best way. See example below:
let userFollowingIDs = ["01","02","03"]
for id in userFollowingIDs {
db.collection("Trips").document(id).collection("userPosts")
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
completion(false)
} else {
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
self.followingTripsList = querySnapshot!.documents.compactMap { querySnapshot -> Trip? in
return try? querySnapshot.data(as: Trip.self)
}
}
completion(true)
}
}
}
I think that this can be done easier. Of course I do not have details of whole system, however looking at this particular problem I would add to every userPosts document new field followedBy. The field would be an array where all following the post user ids (uid) will be stored.
Now checking, if particular posts is followed by particular user can be done by checking if this followedBy array contains this user id. Then it will be possible to use two Firestore features: collectionGroup and arrayContains filter
Then getting list of posts followed by particular user will be extremely simple like this:
db.collectionGroup("userPosts")
.whereField("followedBy", arrayContains: uid)
.getDocuments() { (snapshot, error) in
// ...
No looping and less document got from the Firestore. This should be more effective when it comes to usage cost as well.

How to create a nested multipart / MIME envelope for Email in Go?

I'm trying to figure out how to build multipart/mime envelopes for emails in Go. The following code generates correctly-nested bodies - but the boundaries are not inserted correctly.
You can see a demo on https://play.golang.org/p/XLc4DQFObRn
package main
import (
"bytes"
"fmt"
"io"
"log"
"math/rand"
"mime/multipart"
"mime/quotedprintable"
"net/textproto"
)
// multipart/mixed
// |- multipart/related
// | |- multipart/alternative
// | | |- text/plain
// | | `- text/html
// | `- inlines..
// `- attachments..
func main() {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
var part io.Writer
var err error
// Text Content
part, err = writer.CreatePart(textproto.MIMEHeader{"Content-Type": {"multipart/alternative"}})
if err != nil {
log.Fatal(err)
}
childWriter := multipart.NewWriter(part)
var subpart io.Writer
for _, contentType := range []string{"text/plain", "text/html"} {
subpart, err = CreateQuoteTypePart(childWriter, contentType)
if err != nil {
log.Fatal(err)
}
_, err := subpart.Write([]byte("This is a line of text that needs to be wrapped by quoted-printable before it goes to far.\r\n\r\n"))
if err != nil {
log.Fatal(err)
}
}
// Attachments
filename := fmt.Sprintf("File_%d.jpg", rand.Int31())
part, err = writer.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/octet-stream"}, "Content-Disposition": {"attachment; filename=" + filename}})
if err != nil {
log.Fatal(err)
}
part.Write([]byte("AABBCCDDEEFF"))
writer.Close()
fmt.Print(`From: Bob <bob#example.com>
To: Alice <alias#example.com>
Subject: Formatted text mail
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=`)
fmt.Println(writer.Boundary())
fmt.Println(body.String())
}
// https://github.com/domodwyer/mailyak/blob/master/attachments.go#L142
func CreateQuoteTypePart(writer *multipart.Writer, contentType string) (part io.Writer, err error) {
header := textproto.MIMEHeader{
"Content-Type": []string{contentType},
"Content-Transfer-Encoding": []string{"quoted-printable"},
}
part, err = writer.CreatePart(header)
if err != nil {
return
}
part = quotedprintable.NewWriter(part)
return
}
I want to stick to answers from the standard library (stdlib) and avoid third party attempts to wing it.
Unfortunately, the standard library support for writing multi-part MIME messages has a bad API for nesting. The problem is that you have to set the boundary string in the header before creating the writer, but the generated boundary string is obviously not available before creating the writer. So you have to set the boundary strings explicitly.
Here is my solution (runnable in the Go Playground), simplified for brevity. I have chosen to use the outer writer's boundary to set the inner one, and added labels to make it easier to keep track when reading the output.
package main
import ("bytes"; "fmt"; "io"; "log"; "math/rand"; "mime/multipart"; "net/textproto")
// multipart/mixed
// |- multipart/related
// | |- multipart/alternative
// | | |- text/plain
// | | `- text/html
// | `- inlines..
// `- attachments..
func main() {
mixedContent := &bytes.Buffer{}
mixedWriter := multipart.NewWriter(mixedContent)
// related content, inside mixed
var newBoundary = "RELATED-" + mixedWriter.Boundary()
mixedWriter.SetBoundary(first70("MIXED-" + mixedWriter.Boundary()))
relatedWriter, newBoundary := nestedMultipart(mixedWriter, "multipart/related", newBoundary)
altWriter, newBoundary := nestedMultipart(relatedWriter, "multipart/alternative", "ALTERNATIVE-" + newBoundary)
// Actual content alternatives (finally!)
var childContent io.Writer
childContent, _ = altWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {"text/plain"}})
childContent.Write([]byte("This is a line of text\r\n\r\n"))
childContent, _ = altWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {"text/html"}})
childContent.Write([]byte("<html>HTML goes here\r\n</html>\r\n"))
altWriter.Close()
relatedWriter.Close()
// Attachments
filename := fmt.Sprintf("File_%d.jpg", rand.Int31())
var fileContent io.Writer
fileContent, _ = mixedWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/octet-stream"}, "Content-Disposition": {"attachment; filename=" + filename}})
fileContent.Write([]byte("AABBCCDDEEFF"))
mixedWriter.Close()
fmt.Print(`From: Bob <bob#example.com>
To: Alice <alias#example.com>
Subject: Formatted text mail
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=`)
fmt.Print(mixedWriter.Boundary(), "\n\n")
fmt.Println(mixedContent.String())
}
func nestedMultipart(enclosingWriter *multipart.Writer, contentType, boundary string) (nestedWriter *multipart.Writer, newBoundary string) {
var contentBuffer io.Writer
var err error
boundary = first70(boundary)
contentWithBoundary := contentType + "; boundary=\"" + boundary + "\""
contentBuffer, err = enclosingWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {contentWithBoundary}})
if err != nil {
log.Fatal(err)
}
nestedWriter = multipart.NewWriter(contentBuffer)
newBoundary = nestedWriter.Boundary()
nestedWriter.SetBoundary(boundary)
return
}
func first70(str string) string {
if len(str) > 70 {
return string(str[0:69])
}
return str
}

Go optional fields with SQLX

I'm learning Go and am trying to create an api endpoint that has an 'fields' parameter. When I try to scan the sqlx resulting rows it into a struct,however the fields omitted by the user are being returned as as an empty string. Is there a way that I can change the struct to reflect only the fields that the user passed? I don't think I want to use omitempty in case for example user_name is an empty string.
type User struct {
Id int `db:"id"`
UserName string `db:"user_name"`
}
func GetUsers(w http.ResponseWriter,r *http.Request,db *sqlx.DB) {
acceptedFields := map[string]bool {
"id":true,
"user_name":true,
}
var requestedFields string = "id"
if r.URL.Query().Get("fields") != ""{
requestedFields = r.URL.Query().Get("fields");
}
for _, requestedField := range strings.Split(requestedFields,",") {
if !acceptedFields[requestedField] {
http.Error(w, fmt.Sprintf("Unknown Field '%s'",requestedField), http.StatusBadRequest)
}
}
users := []User{}
err := db.Select(&users,fmt.Sprintf("SELECT %s FROM users",requestedFields));
if err != nil {
log.Fatal(err)
}
response, _ := json.Marshal(users)
fmt.Fprintf(w,string(response))
}
Resulting Endpoint Output
/users?fields=id => [{"Id":12,"UserName":""}]
Desired Endpoint Output
/users?fields=id => [{"Id":12}]
Also using sql.NullString results in this:
[{"Id":12,"UserName":{"String":"","Valid":false}}]
Thanks to mkorpriva here is a solution
type User struct {
Id int `db:"id"`
UserName *string `db:"user_name" json:",omitempty"`
}