Sfoglia il codice sorgente

Added rait limit and user functionality

Thisnthat 3 anni fa
parent
commit
652718e69a
7 ha cambiato i file con 236 aggiunte e 35 eliminazioni
  1. 1 1
      about.go
  2. 2 2
      dashboard.go
  3. 0 6
      groups.go
  4. 44 4
      http.go
  5. 3 3
      topics.go
  6. 58 0
      types.go
  7. 128 19
      users.go

+ 1 - 1
about.go

@@ -24,7 +24,7 @@ func GetAbout(config APIConfig) (About, error) {
 	url := fmt.Sprintf("%s/about.json", config.Endpoint)
 
 	req, _ := newGetRequest(config, url)
-	client := getClient()
+	client := getClient(rl)
 	response, err := client.Do(req)
 
 	if err != nil {

+ 2 - 2
dashboard.go

@@ -34,7 +34,7 @@ func GetDashboard(config APIConfig) (Dashboard, error) {
 	url := fmt.Sprintf("%s/admin/dashboard.json", config.Endpoint)
 
 	req, _ := newGetRequest(config, url)
-	client := getClient()
+	client := getClient(rl)
 	response, err := client.Do(req)
 
 	if err != nil {
@@ -56,7 +56,7 @@ func GetVersionCheck(config APIConfig) (VersionCheck, error) {
 	url := fmt.Sprintf("%s/admin/version_check.json", config.Endpoint)
 
 	req, _ := newGetRequest(config, url)
-	client := getClient()
+	client := getClient(rl)
 	response, err := client.Do(req)
 
 	if err != nil {

+ 0 - 6
groups.go

@@ -1,7 +1 @@
 package discourse
-
-// Group - A Discourse group
-type Group struct {
-	ID   int    `json:"id"`
-	Name string `json:"name"`
-}

+ 44 - 4
http.go

@@ -2,10 +2,50 @@ package discourse
 
 import (
 	"bytes"
+	"context"
 	"net/http"
 	"time"
+
+	"golang.org/x/time/rate"
 )
 
+var rl *rate.Limiter
+
+func init() {
+	rl = rate.NewLimiter(rate.Every(1*time.Second), 1)
+}
+
+//RLHTTPClient Rate Limited HTTP Client
+type RLHTTPClient struct {
+	client      *http.Client
+	Ratelimiter *rate.Limiter
+}
+
+//Do dispatches the HTTP request to the network
+func (c *RLHTTPClient) Do(req *http.Request) (*http.Response, error) {
+	// Comment out the below 5 lines to turn off ratelimiting
+	ctx := context.Background()
+	err := c.Ratelimiter.Wait(ctx) // This is a blocking call. Honors the rate limit
+	if err != nil {
+		return nil, err
+	}
+	resp, err := c.client.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	return resp, nil
+}
+
+//NewClient return http client with a ratelimiter
+func getClient(rl *rate.Limiter) *RLHTTPClient {
+	c := &RLHTTPClient{
+		client:      http.DefaultClient,
+		Ratelimiter: rl,
+	}
+
+	return c
+}
+
 func newGetRequest(config APIConfig, url string) (*http.Request, error) {
 	req, err := http.NewRequest("GET", url, nil)
 	req.Header.Set("Api-Key", config.APIKey)
@@ -24,8 +64,8 @@ func newPostRequest(config APIConfig, url string, payload []byte) (*http.Request
 	return req, err
 }
 
-func getClient() *http.Client {
-	client := &http.Client{Timeout: time.Second * 5}
+// func getClient() *http.Client {
+// 	client := &http.Client{Timeout: time.Second * 5}
 
-	return client
-}
+// 	return client
+// }

+ 3 - 3
topics.go

@@ -6,7 +6,7 @@ import (
 	"strings"
 )
 
-type topic struct {
+type pmPayload struct {
 	Body            string `json:"raw"`
 	TargetUsernames string `json:"target_usernames"`
 	Title           string `json:"title"`
@@ -26,7 +26,7 @@ const pmArchtype = "private_message"
 
 // SendPM - Send a PM on the discouse forum
 func SendPM(apiConfig APIConfig, recipients []string, title, body string) (int, error) {
-	newPm := topic{
+	newPm := pmPayload{
 		ArchType:        pmArchtype,
 		TargetUsernames: strings.Join(recipients, ","),
 		Title:           title,
@@ -38,7 +38,7 @@ func SendPM(apiConfig APIConfig, recipients []string, title, body string) (int,
 	url := fmt.Sprintf("%s/posts.json", apiConfig.Endpoint)
 
 	req, _ := newPostRequest(apiConfig, url, payload)
-	client := getClient()
+	client := getClient(rl)
 
 	response, err := client.Do(req)
 

+ 58 - 0
types.go

@@ -0,0 +1,58 @@
+package discourse
+
+// UserResponse - Structure of a discourse user api response// UserResponse - Structure of a discourse user api response
+type UserResponse struct {
+	User      User     `json:"user"`
+	Errors    []string `json:"errors"`
+	ErrorType string   `json:"error_type"`
+}
+
+type UserClass struct {
+	UserBadges []interface{} `json:"user_badges"`
+	User       User          `json:"user"`
+}
+
+// User - A discoruse User
+type User struct {
+	ID         int     `json:"id" schema:"external_id"`
+	Username   string  `json:"username"`
+	CanSendPM  bool    `json:"can_send_private_messages"`
+	Moderator  bool    `json:"moderator"`
+	Admin      bool    `json:"admin"`
+	TrustLevel int64   `json:"trust_level"`
+	Groups     []Group `json:"groups"`
+	GroupStr   string  `schema:"groups"`
+	Staged     bool    `json:"staged"`
+}
+
+type Group struct {
+	ID                        int64  `json:"id"`
+	Automatic                 bool   `json:"automatic"`
+	Name                      string `json:"name"`
+	DisplayName               string `json:"display_name"`
+	UserCount                 int64  `json:"user_count"`
+	MentionableLevel          int64  `json:"mentionable_level"`
+	MessageableLevel          int64  `json:"messageable_level"`
+	VisibilityLevel           int64  `json:"visibility_level"`
+	PrimaryGroup              bool   `json:"primary_group"`
+	Title                     string `json:"title"`
+	GrantTrustLevel           int64  `json:"grant_trust_level"`
+	IncomingEmail             string `json:"incoming_email"`
+	HasMessages               bool   `json:"has_messages"`
+	FlairURL                  string `json:"flair_url"`
+	FlairBgColor              string `json:"flair_bg_color"`
+	FlairColor                string `json:"flair_color"`
+	BioRaw                    string `json:"bio_raw"`
+	BioCooked                 string `json:"bio_cooked"`
+	BioExcerpt                string `json:"bio_excerpt"`
+	PublicAdmission           bool   `json:"public_admission"`
+	PublicExit                bool   `json:"public_exit"`
+	AllowMembershipRequests   bool   `json:"allow_membership_requests"`
+	FullName                  string `json:"full_name"`
+	DefaultNotificationLevel  int64  `json:"default_notification_level"`
+	MembershipRequestTemplate string `json:"membership_request_template"`
+	MembersVisibilityLevel    int64  `json:"members_visibility_level"`
+	CanSeeMembers             bool   `json:"can_see_members"`
+	CanAdminGroup             bool   `json:"can_admin_group"`
+	PublishReadState          bool   `json:"publish_read_state"`
+}

+ 128 - 19
users.go

@@ -3,34 +3,96 @@ package discourse
 import (
 	"encoding/json"
 	"fmt"
+	"io/ioutil"
 	"strings"
+	"time"
+
+	"github.com/sirupsen/logrus"
 )
 
 // UserResponse - Structure of a discourse user api response// UserResponse - Structure of a discourse user api response
-type UserResponse struct {
-	User      User     `json:"user"`
-	Errors    []string `json:"errors"`
-	ErrorType string   `json:"error_type"`
-}
+// type UserResponse struct {
+// 	User      User     `json:"user"`
+// 	Errors    []string `json:"errors"`
+// 	ErrorType string   `json:"error_type"`
+// }
 
 // User - A discoruse User
-type User struct {
-	ID         int     `json:"id" schema:"external_id"`
-	Username   string  `json:"username"`
-	CanSendPM  bool    `json:"can_send_private_messages"`
-	Moderator  bool    `json:"moderator"`
-	Admin      bool    `json:"admin"`
-	TrustLevel int     `json:"trust_level"`
-	Groups     []Group `json:"groups"`
-	GroupStr   string  `schema:"groups"`
-}
+// type User struct {
+// 	ID         int     `json:"id" schema:"external_id"`
+// 	Username   string  `json:"username"`
+// 	CanSendPM  bool    `json:"can_send_private_messages"`
+// 	Moderator  bool    `json:"moderator"`
+// 	Admin      bool    `json:"admin"`
+// 	TrustLevel int     `json:"trust_level"`
+// 	Groups     []Group `json:"groups"`
+// 	GroupStr   string  `schema:"groups"`
+// }
+
+// Generated by https://quicktype.io
+
+// type User struct {
+// 	ID                     int64         `json:"id"`
+// 	Username               string        `json:"username"`
+// 	Name                   interface{}   `json:"name"`
+// 	AvatarTemplate         string        `json:"avatar_template"`
+// 	Email                  string        `json:"email"`
+// 	SecondaryEmails        []interface{} `json:"secondary_emails"`
+// 	Active                 bool          `json:"active"`
+// 	Admin                  bool          `json:"admin"`
+// 	Moderator              bool          `json:"moderator"`
+// 	LastSeenAt             interface{}   `json:"last_seen_at"`
+// 	LastEmailedAt          interface{}   `json:"last_emailed_at"`
+// 	CreatedAt              string        `json:"created_at"`
+// 	LastSeenAge            interface{}   `json:"last_seen_age"`
+// 	LastEmailedAge         interface{}   `json:"last_emailed_age"`
+// 	CreatedAtAge           interface{}   `json:"created_at_age"`
+// 	TrustLevel             int64         `json:"trust_level"`
+// 	ManualLockedTrustLevel interface{}   `json:"manual_locked_trust_level"`
+// 	FlagLevel              int64         `json:"flag_level"`
+// 	Title                  interface{}   `json:"title"`
+// 	TimeRead               int64         `json:"time_read"`
+// 	Staged                 bool          `json:"staged"`
+// 	DaysVisited            int64         `json:"days_visited"`
+// 	PostsReadCount         int64         `json:"posts_read_count"`
+// 	TopicsEntered          int64         `json:"topics_entered"`
+// 	PostCount              int64         `json:"post_count"`
+// }
+
+// Generated by https://quicktype.io
+
+// type GroupMembers struct {
+// 	Members   []Member `json:"members"`
+// 	Owners    []Member `json:"owners"`
+// 	Meta      Meta     `json:"meta"`
+// 	Errors    []string `json:"errors"`
+// 	ErrorType string   `json:"error_type"`
+// }
+
+// type Member struct {
+// 	ID             int64       `json:"id"`
+// 	Username       string      `json:"username"`
+// 	Name           interface{} `json:"name"`
+// 	AvatarTemplate string      `json:"avatar_template"`
+// 	Title          interface{} `json:"title"`
+// 	LastPostedAt   string      `json:"last_posted_at"`
+// 	LastSeenAt     string      `json:"last_seen_at"`
+// 	AddedAt        string      `json:"added_at"`
+// 	Timezone       string      `json:"timezone"`
+// }
+
+// type Meta struct {
+// 	Total  int64 `json:"total"`
+// 	Limit  int64 `json:"limit"`
+// 	Offset int64 `json:"offset"`
+// }
 
 // GetUser - Get a discourse user
 func GetUser(config APIConfig, username string) (User, error) {
 	url := fmt.Sprintf("%s/users/%s.json", config.Endpoint, username)
-
+	fmt.Println(url)
 	req, _ := newGetRequest(config, url)
-	client := getClient()
+	client := getClient(rl)
 	response, _ := client.Do(req)
 
 	var result *UserResponse
@@ -47,7 +109,7 @@ func GetUserByID(config APIConfig, userID int) (User, error) {
 	url := fmt.Sprintf("%s/admin/users/%d.json", config.Endpoint, userID)
 
 	req, _ := newGetRequest(config, url)
-	client := getClient()
+	client := getClient(rl)
 	response, _ := client.Do(req)
 
 	var result *UserResponse
@@ -58,4 +120,51 @@ func GetUserByID(config APIConfig, userID int) (User, error) {
 	}
 
 	return result.User, nil
-}
+}
+
+func GetUsersByMinTrustLevel(config APIConfig, minTrustLevel int64) ([]User, error) {
+	page := 1
+	getMoreResults := true
+
+	var users []User
+
+	for getMoreResults {
+		var pageResults, _ = GetUsersPage(config, page)
+		if len(pageResults) > 0 {
+			for _, v := range pageResults {
+				if v.Staged == false && v.TrustLevel >= minTrustLevel {
+					u, err := GetUser(config, v.Username)
+					if err != nil {
+						return nil, err
+					}
+					users = append(users, u)
+				}
+			}
+			page++
+		} else {
+			getMoreResults = false
+		}
+	}
+
+	return users, nil
+}
+
+func GetUsersPage(config APIConfig, page int) ([]User, error) {
+	url := fmt.Sprintf("%s/admin/users/list/active.json?page=%d&?filter=&show_emails=false", config.Endpoint, page)
+	fmt.Println(url)
+	req, _ := newGetRequest(config, url)
+	client := getClient(rl)
+	response, _ := client.Do(req)
+	time.Sleep(1 * time.Second)
+
+	bodyBytes, err := ioutil.ReadAll(response.Body)
+	if err != nil {
+		logrus.Fatal(err)
+	}
+
+	var users []User
+
+	json.Unmarshal(bodyBytes, &users)
+
+	return users, nil
+}