Page MenuHomeMusing Studio

No OneTemporary

diff --git a/auth.go b/auth.go
index e66f0bb..ffba97d 100644
--- a/auth.go
+++ b/auth.go
@@ -1,75 +1,77 @@
package writeas
import (
"fmt"
"net/http"
)
// LogIn authenticates a user with Write.as.
// See https://developer.write.as/docs/api/#authenticate-a-user
func (c *Client) LogIn(username, pass string) (*AuthUser, error) {
u := &AuthUser{}
up := struct {
Alias string `json:"alias"`
Pass string `json:"pass"`
}{
Alias: username,
Pass: pass,
}
env, err := c.post("/auth/login", up, u)
if err != nil {
return nil, err
}
var ok bool
if u, ok = env.Data.(*AuthUser); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
+ u.BaseURL = c.BaseUrl()
+
status := env.Code
if status != http.StatusOK {
if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
} else if status == http.StatusUnauthorized {
return nil, fmt.Errorf("Incorrect password.")
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("User does not exist.")
} else if status == http.StatusTooManyRequests {
return nil, fmt.Errorf("Stop repeatedly trying to log in.")
}
return nil, fmt.Errorf("Problem authenticating: %d. %v\n", status, err)
}
c.SetToken(u.AccessToken)
return u, nil
}
// LogOut logs the current user out, making the Client's current access token
// invalid.
func (c *Client) LogOut() error {
env, err := c.delete("/auth/me", nil)
if err != nil {
return err
}
status := env.Code
if status != http.StatusNoContent {
if status == http.StatusNotFound {
return fmt.Errorf("Access token is invalid or doesn't exist")
}
return fmt.Errorf("Unable to log out: %v", env.ErrorMessage)
}
// Logout successful, so update the Client
c.token = ""
return nil
}
func (c *Client) isNotLoggedIn(code int) bool {
if c.token == "" {
return false
}
return code == http.StatusUnauthorized
}
diff --git a/user.go b/user.go
index 5973d9c..1e150a5 100644
--- a/user.go
+++ b/user.go
@@ -1,34 +1,35 @@
package writeas
import "time"
type (
// AuthUser represents a just-authenticated user. It contains information
// that'll only be returned once (now) per user session.
AuthUser struct {
+ BaseURL string `json:"baseUrl,omitempty"`
AccessToken string `json:"access_token,omitempty"`
Password string `json:"password,omitempty"`
User *User `json:"user"`
}
// User represents a registered Write.as user.
User struct {
Username string `json:"username"`
Email string `json:"email"`
Created time.Time `json:"created"`
// Optional properties
Subscription *UserSubscription `json:"subscription"`
}
// UserSubscription contains information about a user's Write.as
// subscription.
UserSubscription struct {
Name string `json:"name"`
Begin time.Time `json:"begin"`
End time.Time `json:"end"`
AutoRenew bool `json:"auto_renew"`
Active bool `json:"is_active"`
Delinquent bool `json:"is_delinquent"`
}
)
diff --git a/writeas.go b/writeas.go
index fa87ae1..785c044 100644
--- a/writeas.go
+++ b/writeas.go
@@ -1,199 +1,211 @@
// Package writeas provides the binding for the Write.as API
package writeas
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"code.as/core/socks"
"github.com/writeas/impart"
)
const (
apiURL = "https://write.as/api"
devAPIURL = "https://development.write.as/api"
torAPIURL = "http://writeas7pm7rcdqg.onion/api"
// Current go-writeas version
Version = "2-dev"
)
// Client is used to interact with the Write.as API. It can be used to make
// authenticated or unauthenticated calls.
type Client struct {
baseURL string
// Access token for the user making requests.
token string
// Client making requests to the API
client *http.Client
// UserAgent overrides the default User-Agent header
UserAgent string
}
// defaultHTTPTimeout is the default http.Client timeout.
const defaultHTTPTimeout = 10 * time.Second
// NewClient creates a new API client. By default, all requests are made
// unauthenticated. To optionally make authenticated requests, call `SetToken`.
//
// c := writeas.NewClient()
// c.SetToken("00000000-0000-0000-0000-000000000000")
func NewClient() *Client {
return NewClientWith(Config{URL: apiURL})
}
// NewTorClient creates a new API client for communicating with the Write.as
// Tor hidden service, using the given port to connect to the local SOCKS
// proxy.
func NewTorClient(port int) *Client {
return NewClientWith(Config{URL: torAPIURL, TorPort: port})
}
// NewDevClient creates a new API client for development and testing. It'll
// communicate with our development servers, and SHOULD NOT be used in
// production.
func NewDevClient() *Client {
return NewClientWith(Config{URL: devAPIURL})
}
// Config configures a Write.as client.
type Config struct {
// URL of the Write.as API service. Defaults to https://write.as/api.
URL string
// If specified, the API client will communicate with the Write.as Tor
// hidden service using the provided port to connect to the local SOCKS
// proxy.
TorPort int
// If specified, requests will be authenticated using this user token.
// This may be provided after making a few anonymous requests with
// SetToken.
Token string
}
// NewClientWith builds a new API client with the provided configuration.
func NewClientWith(c Config) *Client {
if c.URL == "" {
c.URL = apiURL
}
httpClient := &http.Client{Timeout: defaultHTTPTimeout}
if c.TorPort > 0 {
dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, fmt.Sprintf("127.0.0.1:%d", c.TorPort))
httpClient.Transport = &http.Transport{Dial: dialSocksProxy}
}
return &Client{
client: httpClient,
baseURL: c.URL,
token: c.Token,
}
}
// SetToken sets the user token for all future Client requests. Setting this to
// an empty string will change back to unauthenticated requests.
func (c *Client) SetToken(token string) {
c.token = token
}
// Token returns the user token currently set to the Client.
func (c *Client) Token() string {
return c.token
}
+// SetBaseUrl sets the baseUrl for all future Client requests
+func (c *Client) SetBaseUrl(baseUrl string) {
+ if baseUrl != "" {
+ c.baseURL = baseUrl
+ }
+}
+
+// BaseUrl returns the set baseUrl
+func (c *Client) BaseUrl() string {
+ return c.baseURL
+}
+
func (c *Client) get(path string, r interface{}) (*impart.Envelope, error) {
method := "GET"
if method != "GET" && method != "HEAD" {
return nil, fmt.Errorf("Method %s not currently supported by library (only HEAD and GET).\n", method)
}
return c.request(method, path, nil, r)
}
func (c *Client) post(path string, data, r interface{}) (*impart.Envelope, error) {
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(data)
return c.request("POST", path, b, r)
}
func (c *Client) put(path string, data, r interface{}) (*impart.Envelope, error) {
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(data)
return c.request("PUT", path, b, r)
}
func (c *Client) delete(path string, data map[string]string) (*impart.Envelope, error) {
r, err := c.buildRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
q := r.URL.Query()
for k, v := range data {
q.Add(k, v)
}
r.URL.RawQuery = q.Encode()
return c.doRequest(r, nil)
}
func (c *Client) request(method, path string, data io.Reader, result interface{}) (*impart.Envelope, error) {
r, err := c.buildRequest(method, path, data)
if err != nil {
return nil, err
}
return c.doRequest(r, result)
}
func (c *Client) buildRequest(method, path string, data io.Reader) (*http.Request, error) {
url := fmt.Sprintf("%s%s", c.baseURL, path)
r, err := http.NewRequest(method, url, data)
if err != nil {
return nil, fmt.Errorf("Create request: %v", err)
}
c.prepareRequest(r)
return r, nil
}
func (c *Client) doRequest(r *http.Request, result interface{}) (*impart.Envelope, error) {
resp, err := c.client.Do(r)
if err != nil {
return nil, fmt.Errorf("Request: %v", err)
}
defer resp.Body.Close()
env := &impart.Envelope{
Code: resp.StatusCode,
}
if result != nil {
env.Data = result
err = json.NewDecoder(resp.Body).Decode(&env)
if err != nil {
return nil, err
}
}
return env, nil
}
func (c *Client) prepareRequest(r *http.Request) {
ua := c.UserAgent
if ua == "" {
ua = "go-writeas v" + Version
}
r.Header.Set("User-Agent", ua)
r.Header.Add("Content-Type", "application/json")
if c.token != "" {
r.Header.Add("Authorization", "Token "+c.token)
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 1:59 PM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3106698

Event Timeline