diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..d890f64 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,15 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/sadbox/mediawiki" + packages = ["."] + revision = "39fea8a1336076a961a300d1d95765dcd17e8a3c" + version = "v0.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "875ef87fe71f1595d9be3e43d2eba538fdb3c449361cf31b521971c297745867" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..ce4da32 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,34 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/sadbox/mediawiki" + version = "0.1.0" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/sadbox/mediawiki/.gitignore b/vendor/github.com/sadbox/mediawiki/.gitignore new file mode 100644 index 0000000..f2c7807 --- /dev/null +++ b/vendor/github.com/sadbox/mediawiki/.gitignore @@ -0,0 +1,25 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe + +/examples/examples +/examples/config.xml diff --git a/vendor/github.com/sadbox/mediawiki/LICENSE b/vendor/github.com/sadbox/mediawiki/LICENSE new file mode 100644 index 0000000..5f3a518 --- /dev/null +++ b/vendor/github.com/sadbox/mediawiki/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 James McGuire + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/sadbox/mediawiki/README.md b/vendor/github.com/sadbox/mediawiki/README.md new file mode 100644 index 0000000..891b2ff --- /dev/null +++ b/vendor/github.com/sadbox/mediawiki/README.md @@ -0,0 +1,36 @@ +go-mediawiki [![Build Status](https://drone.io/github.com/sadbox/go-mediawiki/status.png)](https://drone.io/github.com/sadbox/go-mediawiki/latest) +======== +A MediaWiki API wrapper for [Go](http://golang.org/) + +Documentation +------------- +Documentation specific to this implementaiton is [located on GoDoc](http://godoc.org/github.com/sadbox/go-mediawiki) + +Documentation specific to the Mediawiki API in general is located [at their own wiki](http://www.mediawiki.org/wiki/API:Main_page) + +Examples are located in the [examples subdirectory.](/examples) + + +TODO +---- +- ☑ Login/Logout +- ☑ Edit Pages +- ☑ Read Pages +- ☑ Upload +- ☑ Download +- ☑ Generic API Interface +- ☑ Unit tests + +Useful Links +------------ +For easy handling of items that you get back from client.API() + +https://github.com/jmoiron/jsonq + +For adding your own structs + +https://github.com/str1ngs/jflect + +License +------- +This software is licensed under the MIT license. Pull requests and issues are welcome. diff --git a/vendor/github.com/sadbox/mediawiki/mediawiki.go b/vendor/github.com/sadbox/mediawiki/mediawiki.go new file mode 100644 index 0000000..af60cb9 --- /dev/null +++ b/vendor/github.com/sadbox/mediawiki/mediawiki.go @@ -0,0 +1,496 @@ +// Copyright 2013 James McGuire +// This code is covered under the MIT License +// Please refer to the LICENSE file in the root of this +// repository for any information. + +// go-mediawiki provides a wrapper for interacting with the Mediawiki API +// +// Please see http://www.mediawiki.org/wiki/API:Main_page +// for any API specific information or refer to any of the +// functions defined for the MWApi struct for information +// regarding this specific implementation. +// +// The client subdirectory contains an example application +// that uses this API. +package mediawiki + +import ( + "bytes" + "encoding/json" + "errors" + "io" + "io/ioutil" + "mime/multipart" + "net/http" + "net/http/cookiejar" + "net/url" + "strings" +) + +// The main mediawiki API struct, this is generated via mwapi.New() +type MWApi struct { + Username string + Password string + Domain string + userAgent string + debug bool + url *url.URL + client *http.Client + format string + edittoken string +} + +// This is used for passing data to the mediawiki API via key=value in a POST +type Values map[string]string + +// Unmarshal login data... +type outerLogin struct { + Login loginResponse +} + +type loginResponse struct { + Result string + Token string +} + +// Unmarshall response from page edits... +type outerEdit struct { + Edit edit +} + +type edit struct { + Result string + PageId int + Title string + OldRevId int + NewRevId int +} + +// General query response from mediawiki +type mwQuery struct { + Query query +} + +type query struct { + Pages map[string]page +} + +type page struct { + Pageid int + Ns float64 + Title string + Touched string + Lastrevid float64 + // This will appear as both a string and a number... and the JSON unmarshaler + // will crap out if this isn't set to a string. + //Counter string + Length float64 + Edittoken string + Revisions []revision + Imageinfo []image +} + +type revision struct { + Body string `json:"*"` + User string + Timestamp string + comment string +} + +type image struct { + Url string + Descriptionurl string +} + +type mwError struct { + Error errorType +} + +type errorType struct { + Code string + Info string +} + +type uploadResponse struct { + Upload uploadResult +} + +type uploadResult struct { + Result string +} + +// Helper function for translating mediawiki errors in to golang errors. +func CheckError(response []byte) error { + var mwerror mwError + err := json.Unmarshal(response, &mwerror) + if err != nil { + return nil + } else if mwerror.Error.Code != "" { + return errors.New(mwerror.Error.Code + ": " + mwerror.Error.Info) + } else { + return nil + } +} + +// Generate a new mediawiki API struct +// +// Example: mwapi.New("http://en.wikipedia.org/w/api.php", "My Mediawiki Bot") +// Returns errors if the URL is invalid +func New(wikiUrl, userAgent string) (*MWApi, error) { + cookiejar, err := cookiejar.New(nil) + if err != nil { + return nil, err + } + + client := http.Client{ + Transport: nil, + CheckRedirect: nil, + Jar: cookiejar, + } + + clientUrl, err := url.Parse(wikiUrl) + if err != nil { + return nil, err + } + + return &MWApi{ + url: clientUrl, + client: &client, + format: "json", + userAgent: "go-mediawiki https://github.com/sadbox/go-mediawiki " + userAgent, + debug: false, + }, nil +} + +// This will automatically add the user agent and encode the http request properly +func (m *MWApi) postForm(query url.Values) ([]byte, error) { + request, err := http.NewRequest("POST", m.url.String(), strings.NewReader(query.Encode())) + if err != nil { + return nil, err + } + request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + request.Header.Set("user-agent", m.userAgent) + resp, err := m.client.Do(request) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if err = CheckError(body); err != nil { + return nil, err + } + + return body, nil +} + +// Download a file. +// +// Returns a readcloser that must be closed manually. Refer to the +// example app for additional usage. +func (m *MWApi) Download(filename string) (io.ReadCloser, error) { + // First get the direct url of the file + query := Values{ + "action": "query", + "prop": "imageinfo", + "iiprop": "url", + "titles": filename, + } + + body, _, err := m.API(query) + if err != nil { + return nil, err + } + + var response mwQuery + err = json.Unmarshal(body, &response) + if err != nil { + return nil, err + } + + var fileurl string + for _, page := range response.Query.Pages { + if len(page.Imageinfo) < 1 { + return nil, errors.New("No file found") + } + fileurl = page.Imageinfo[0].Url + break + } + + // Then return the body of the response + request, err := http.NewRequest("GET", fileurl, nil) + if err != nil { + return nil, err + } + request.Header.Set("user-agent", m.userAgent) + + resp, err := m.client.Do(request) + if err != nil { + return nil, err + } + return resp.Body, nil +} + +// Upload a file +// +// This does a simple, but more error-prone upload. Mediawiki +// has a chunked upload version but it is only available in newer +// versions of the API. +// +// Automatically retrieves an edit token if necessary. +func (m *MWApi) Upload(dstFilename string, file io.Reader) error { + if m.edittoken == "" { + err := m.GetEditToken() + if err != nil { + return err + } + } + + query := Values{ + "action": "upload", + "filename": dstFilename, + "token": m.edittoken, + "format": m.format, + } + + buffer := &bytes.Buffer{} + writer := multipart.NewWriter(buffer) + + for key, value := range query { + err := writer.WriteField(key, value) + if err != nil { + return err + } + } + + part, err := writer.CreateFormFile("file", dstFilename) + _, err = io.Copy(part, file) + if err != nil { + return err + } + + err = writer.Close() + if err != nil { + return err + } + + request, err := http.NewRequest("POST", m.url.String(), buffer) + if err != nil { + return err + } + request.Header.Set("Content-Type", "multipart/form-data; boundary="+writer.Boundary()) + request.Header.Set("user-agent", m.userAgent) + + resp, err := m.client.Do(request) + if err != nil { + return err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + if err = CheckError(body); err != nil { + return err + } + + var response uploadResponse + err = json.Unmarshal(body, &response) + if err != nil { + return err + } + if response.Upload.Result == "Success" || response.Upload.Result == "Warning" { + return nil + } else { + return errors.New(response.Upload.Result) + } +} + +// Login to the Mediawiki Website +// +// This will throw an error if you didn't define a username +// or password. +func (m *MWApi) Login() error { + if m.Username == "" || m.Password == "" { + return errors.New("Username or password not set.") + } + + query := Values{ + "action": "login", + "lgname": m.Username, + "lgpassword": m.Password, + } + + if m.Domain != "" { + query["lgdomain"] = m.Domain + } + + body, _, err := m.API(query) + if err != nil { + return err + } + + var response outerLogin + err = json.Unmarshal(body, &response) + if err != nil { + return err + } + + if response.Login.Result == "Success" { + return nil + } else if response.Login.Result != "NeedToken" { + return errors.New("Error logging in: " + response.Login.Result) + } + + // Need to use the login token + query["lgtoken"] = response.Login.Token + + body, _, err = m.API(query) + if err != nil { + return err + } + + err = json.Unmarshal(body, &response) + if err != nil { + return err + } + + if response.Login.Result == "Success" { + return nil + } else { + return errors.New("Error logging in: " + response.Login.Result) + } +} + +// Get an edit token +// +// This is necessary for editing any page. +// +// The Edit() function will call this automatically +// but it is available if you want to make direct +// calls to API(). +func (m *MWApi) GetEditToken() error { + query := Values{ + "action": "query", + "prop": "info|revisions", + "intoken": "edit", + "titles": "Main Page", + } + + body, _, err := m.API(query) + if err != nil { + return err + } + var response mwQuery + err = json.Unmarshal(body, &response) + if err != nil { + return err + } + for _, value := range response.Query.Pages { + m.edittoken = value.Edittoken + break + } + return nil +} + +// Log out of the mediawiki website +func (m *MWApi) Logout() { + m.API(Values{"action": "logout"}) +} + +// Edit a page +// +// This function will automatically grab an Edit Token if there +// is not one currently stored. +// +// Example: +// +// editConfig := mediawiki.Values{ +// "title": "SOME PAGE", +// "summary": "THIS IS WHAT SHOWS UP IN THE LOG", +// "text": "THE ENTIRE TEXT OF THE PAGE", +// } +// err = client.Edit(editConfig) +func (m *MWApi) Edit(values Values) error { + if m.edittoken == "" { + err := m.GetEditToken() + if err != nil { + return err + } + } + query := Values{ + "action": "edit", + "token": m.edittoken, + } + body, _, err := m.API(query, values) + if err != nil { + return err + } + + var response outerEdit + err = json.Unmarshal(body, &response) + if err != nil { + return err + } + + if response.Edit.Result == "Success" { + return nil + } else { + return errors.New(response.Edit.Result) + } +} + +// Request a wiki page and it's metadata. +func (m *MWApi) Read(pageName string) (*revision, error) { + query := Values{ + "action": "query", + "prop": "revisions", + "titles": pageName, + "rvlimit": "1", + "rvprop": "content|timestamp|user|comment", + } + body, _, err := m.API(query) + + var response mwQuery + err = json.Unmarshal(body, &response) + if err != nil { + return nil, err + } + for _, page := range response.Query.Pages { + return &page.Revisions[0], nil + } + return nil, errors.New("No revisions found") +} + +// A generic interface to the Mediawiki API +// Refer to the mediawiki API reference for any information regarding +// what to pass to this function +// +// This is used by all internal functions to interact with the API +// +// The second return is simply the json data decoded in to an empty interface +// that can be used by something like https://github.com/jmoiron/jsonq +func (m *MWApi) API(values ...Values) ([]byte, interface{}, error) { + query := m.url.Query() + for _, valuemap := range values { + for key, value := range valuemap { + query.Set(key, value) + } + } + query.Set("format", m.format) + body, err := m.postForm(query) + if err != nil { + return nil, nil, err + } + var unmarshalto interface{} + err = json.Unmarshal(body, &unmarshalto) + if err != nil { + return nil, nil, err + } + return body, unmarshalto, nil +} diff --git a/wikiauth_test.go b/wikiauth_test.go index 12dcfa7..cff0d41 100644 --- a/wikiauth_test.go +++ b/wikiauth_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - "git.aiterp.net/AiteRP/wikiauth" + "git.aiterp.net/aiterp/wikiauth" ) func TestAuth(t *testing.T) {