account.go
changeset 143 9ce9b39c851c
parent 138 23d3a518d0ad
child 149 5f922977d7c7
equal deleted inserted replaced
142:048f390e94c5 143:9ce9b39c851c
     5 */
     5 */
     6 
     6 
     7 package madon
     7 package madon
     8 
     8 
     9 import (
     9 import (
       
    10 	"bytes"
       
    11 	"encoding/base64"
       
    12 	"encoding/json"
    10 	"fmt"
    13 	"fmt"
       
    14 	"mime/multipart"
       
    15 	"net/http"
       
    16 	"os"
    11 	"strconv"
    17 	"strconv"
       
    18 	"strings"
    12 
    19 
    13 	"github.com/sendgrid/rest"
    20 	"github.com/sendgrid/rest"
    14 )
    21 )
    15 
    22 
    16 // getAccountsOptions contains option fields for POST and DELETE API calls
    23 // getAccountsOptions contains option fields for POST and DELETE API calls
   302 		endPoint = "follow_requests/authorize"
   309 		endPoint = "follow_requests/authorize"
   303 	}
   310 	}
   304 	_, err := mc.getSingleAccount(endPoint, accountID)
   311 	_, err := mc.getSingleAccount(endPoint, accountID)
   305 	return err
   312 	return err
   306 }
   313 }
       
   314 
       
   315 // UpdateAccount updates the connected user's account data
       
   316 // The fields avatar & headerImage can contain base64-encoded images; if
       
   317 // they do not (that is; if they don't contain ";base64,"), they are considered
       
   318 // as file paths and their content will be encoded.
       
   319 // All fields can be nil, in which case they are not updated.
       
   320 // displayName and note can be set to "" to delete previous values;
       
   321 // I'm not sure images can be deleted -- only replaced AFAICS.
       
   322 func (mc *Client) UpdateAccount(displayName, note, avatar, headerImage *string) (*Account, error) {
       
   323 	const endPoint = "accounts/update_credentials"
       
   324 	params := make(apiCallParams)
       
   325 
       
   326 	if displayName != nil {
       
   327 		params["display_name"] = *displayName
       
   328 	}
       
   329 	if note != nil {
       
   330 		params["note"] = *note
       
   331 	}
       
   332 
       
   333 	var err error
       
   334 	avatar, err = fileToBase64(avatar, nil)
       
   335 	if err != nil {
       
   336 		return nil, err
       
   337 	}
       
   338 	headerImage, err = fileToBase64(headerImage, nil)
       
   339 	if err != nil {
       
   340 		return nil, err
       
   341 	}
       
   342 
       
   343 	var formBuf bytes.Buffer
       
   344 	w := multipart.NewWriter(&formBuf)
       
   345 
       
   346 	if avatar != nil {
       
   347 		w.WriteField("avatar", *avatar)
       
   348 	}
       
   349 	if headerImage != nil {
       
   350 		w.WriteField("header", *headerImage)
       
   351 	}
       
   352 	w.Close()
       
   353 
       
   354 	// Prepare the request
       
   355 	req, err := mc.prepareRequest(endPoint, rest.Patch, params)
       
   356 	if err != nil {
       
   357 		return nil, fmt.Errorf("prepareRequest failed: %s", err.Error())
       
   358 	}
       
   359 	req.Headers["Content-Type"] = w.FormDataContentType()
       
   360 	req.Body = formBuf.Bytes()
       
   361 
       
   362 	// Make API call
       
   363 	r, err := restAPI(req)
       
   364 	if err != nil {
       
   365 		return nil, fmt.Errorf("account update failed: %s", err.Error())
       
   366 	}
       
   367 
       
   368 	// Check for error reply
       
   369 	var errorResult Error
       
   370 	if err := json.Unmarshal([]byte(r.Body), &errorResult); err == nil {
       
   371 		// The empty object is not an error
       
   372 		if errorResult.Text != "" {
       
   373 			return nil, fmt.Errorf("%s", errorResult.Text)
       
   374 		}
       
   375 	}
       
   376 
       
   377 	// Not an error reply; let's unmarshal the data
       
   378 	var account Account
       
   379 	if err := json.Unmarshal([]byte(r.Body), &account); err != nil {
       
   380 		return nil, fmt.Errorf("cannot decode API response: %s", err.Error())
       
   381 	}
       
   382 	return &account, nil
       
   383 }
       
   384 
       
   385 // fileToBase64 is a helper function to convert a file's contents to
       
   386 // base64-encoded data.  Is the data string already contains base64 data, it
       
   387 // is not modified.
       
   388 // If contentType is nil, it is detected.
       
   389 func fileToBase64(data, contentType *string) (*string, error) {
       
   390 	if data == nil {
       
   391 		return nil, nil
       
   392 	}
       
   393 
       
   394 	if *data == "" {
       
   395 		return data, nil
       
   396 	}
       
   397 
       
   398 	if strings.Contains(*data, ";base64,") {
       
   399 		return data, nil
       
   400 	}
       
   401 
       
   402 	// We need to convert the file and file name to base64
       
   403 
       
   404 	file, err := os.Open(*data)
       
   405 	if err != nil {
       
   406 		return nil, err
       
   407 	}
       
   408 	defer file.Close()
       
   409 
       
   410 	fStat, err := file.Stat()
       
   411 	if err != nil {
       
   412 		return nil, err
       
   413 	}
       
   414 
       
   415 	buffer := make([]byte, fStat.Size())
       
   416 	_, err = file.Read(buffer)
       
   417 	if err != nil {
       
   418 		return nil, err
       
   419 	}
       
   420 
       
   421 	var cType string
       
   422 	if contentType == nil || *contentType == "" {
       
   423 		cType = http.DetectContentType(buffer[:512])
       
   424 	} else {
       
   425 		cType = *contentType
       
   426 	}
       
   427 	contentData := base64.StdEncoding.EncodeToString(buffer)
       
   428 	newData := "data:" + cType + ";base64," + contentData
       
   429 	return &newData, nil
       
   430 }