Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
Signed-off-by: Raphaël Pinson <[email protected]>
  • Loading branch information
raphink committed Sep 11, 2024
1 parent 471d6ae commit ca986b4
Show file tree
Hide file tree
Showing 10 changed files with 816 additions and 1 deletion.
29 changes: 29 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Go

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.23 # Specify a compatible Go version, like 1.20

- name: Install dependencies
run: go mod tidy

- name: Run tests
run: go test ./... -v

66 changes: 65 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,66 @@
# credly-go
A Go library for the Credly API

[![Go Report Card](https://goreportcard.com/badge/github.com/isovalent/credly-go)](https://goreportcard.com/report/github.com/isovalent/credly-go)
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)

`credly-go` is a Go client library for interacting with the Credly platform. It provides a simple and convenient way to programmatically access Credly's APIs and handle badges and templates.

## Features

- **Badge Management**: Issue, retrieve, and manage badges using the Credly API.

## Installation

To install the `credly-go` library, run:

```shell
go get github.com/isovalent/credly-go
```


## Example Usage


```go
package main

import (
"github.com/isovalent/credly-go/credly"
)

func main() {
// Initialize the Credly client
client := credly.NewClient("your-api-token", "your-credly-org")

// Get all badges for user [email protected]
badges, err := client.GetBadges("[email protected]")
}
```

## Contributing

We welcome contributions! Please follow these steps to contribute:

1. Fork the repository.
2. Create a new branch with your feature or bug fix.
3. Make your changes and add tests.
4. Submit a pull request with a detailed description of your changes.

## Running Tests

To run the tests, use:

```shell
go test ./...
```


Make sure to write tests for any new functionality and ensure that all existing tests pass.

## License

This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.

## Support

If you have any questions or need help, feel free to open an issue in the [GitHub repository](https://github.com/isovalent/credly-go/issues).
170 changes: 170 additions & 0 deletions credly/badge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package credly

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
)

// issueBadgeResponse represents the response structure when a badge is issued.
// see https://www.credly.com/docs/issued_badges
type issueBadgeResponse struct {
Data BadgeInfo `json:"data"`
}

// getBadgesResponse represents the response structure when fetching multiple badges.
type getBadgesResponse struct {
Data []BadgeInfo `json:"data"`
}


// BadgeInfo represents the details of an issued badge.
type BadgeInfo struct {
Id string `json:"id"`
ImageUrl string `json:"image_url"`
Url string `json:"badge_url"`
IssuedAt time.Time `json:"issued_at"`
State string `json:"state"`

Image struct {
Url string `json:"url"`
} `json:"image"`

Template BadgeTemplate `json:"badge_template"`

User struct {
Id string `json:"id"`
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Url string `json:"url"`
} `json:"user"`
}


// IssueBadge issues a new badge to a user based on their email and personal details.
//
// templateId: The ID of the badge template to be issued.
// email: The recipient's email address.
// firstName: The recipient's first name.
// lastName: The recipient's last name.
// Returns: BadgeInfo representing the issued badge, or an error if the operation fails.
func (c *Client) IssueBadge(templateId, email, firstName, lastName string) (i BadgeInfo, err error) {
url := fmt.Sprintf("https://api.credly.com/v1/organizations/%s/badges", c.OrganizationId)

now := time.Now()
issuedAt := now.Format("2006-01-02 15:04:05 -0700")

params := map[string]interface{}{
"badge_template_id": templateId,
"recipient_email": email,
"issued_to_first_name": firstName,
"issued_to_last_name": lastName,
"issued_at": issuedAt,
}
reqBody, err := json.Marshal(params)
if err != nil {
return i, fmt.Errorf("[credly.IssueBadge] Failed to marshal parameters: %v", err)
}

req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqBody))
if err != nil {
return i, err
}

resp, err := c.Do(req)
if err != nil {
return i, err
}

defer resp.Body.Close()

if resp.StatusCode == http.StatusUnprocessableEntity {
// Contact already has badge
return i, fmt.Errorf(ErrBadgeAlreadyIssued)
}

if resp.StatusCode != http.StatusCreated {
return i, fmt.Errorf("[credly.IssueBadge] API request failed with status code: %d", resp.StatusCode)
}

var badgeResp issueBadgeResponse
if err := json.NewDecoder(resp.Body).Decode(&badgeResp); err != nil {
return i, fmt.Errorf("[credly.IssueBadge] Failed to parse JSON data: %v", err)
}

return badgeResp.Data, nil
}

// GetBadges retrieves all badges for a given email, optionally filtered by collections.
//
// email: The recipient's email address.
// collections: A list of collection tags to filter badges.
// Returns: A slice of BadgeInfo representing the retrieved badges, or an error if the operation fails.
func (c *Client) GetBadges(email string, collections []string) (b []BadgeInfo, err error) {
qUrl := fmt.Sprintf("https://api.credly.com/v1/organizations/%s/badges", c.OrganizationId)
qUrl = fmt.Sprintf("%s?filter=recipient_email_all::%s", qUrl, url.QueryEscape(email))

if len(collections) > 0 {
colFilter := fmt.Sprintf("|badge_templates[reporting_tags]::%s", strings.Join(collections, ","))
qUrl = fmt.Sprintf("%s%s", qUrl, url.QueryEscape(colFilter))
}

req, err := http.NewRequest("GET", qUrl, nil)
if err != nil {
return b, err
}

resp, err := c.Do(req)
if err != nil {
return b, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return b, fmt.Errorf("[credly.GetBadges] API request failed with status code: %d", resp.StatusCode)
}

var badgesResp getBadgesResponse
if err := json.NewDecoder(resp.Body).Decode(&badgesResp); err != nil {
return b, fmt.Errorf("[credly.GetBadges] Failed to parse JSON data: %v", err)
}

return badgesResp.Data, nil
}

// GetBadge retrieves a specific badge for a given email and badge ID.
//
// email: The recipient's email address.
// badgeId: The ID of the badge to be retrieved.
// Returns: A BadgeInfo representing the retrieved badge, or an error if the operation fails.
func (c *Client) GetBadge(email, badgeId string) (b BadgeInfo, err error) {
url := fmt.Sprintf("https://api.credly.com/v1/organizations/%s/badges", c.OrganizationId)
url = fmt.Sprintf("%s?filter=recipient_email_all::%s|badge_template_id::%s", url, email, badgeId)

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return b, err
}

resp, err := c.Do(req)
if err != nil {
return b, err
}
defer resp.Body.Close()

var badgesResp getBadgesResponse
if err := json.NewDecoder(resp.Body).Decode(&badgesResp); err != nil {
return b, fmt.Errorf("Failed to parse JSON data: %v", err)
}

if len(badgesResp.Data) == 0 {
return b, nil
}

return badgesResp.Data[0], nil
}
87 changes: 87 additions & 0 deletions credly/badge_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@

package credly

import (
"encoding/json"
"fmt"
"net/http"
)

// getBadgeTemplateResponse represents the response structure when fetching a specific badge template.
type getBadgeTemplateResponse struct {
Data BadgeTemplate `json:"data"`
}

// getBadgeTemplatesResponse represents the response structure when fetching multiple badge templates.
type getBadgeTemplatesResponse struct {
Data []BadgeTemplate `json:"data"`
}

// BadgeTemplate represents the details of a badge template in Credly.
type BadgeTemplate struct {
Id string `json:"id,omitempty"`
Name string `json:"name"`
Skills []string `json:"skills"`
Url string `json:"url"`
ImageUrl string `json:"image_url"`
VanitySlug string `json:"vanity_slug"`
}

// GetBadgeTemplate retrieves a specific badge template by its ID.
//
// templateId: The ID of the badge template to be retrieved.
// Returns: A BadgeTemplate representing the retrieved template, or an error if the operation fails.
func (c *Client) GetBadgeTemplate(templateId string) (b BadgeTemplate, err error) {
url := fmt.Sprintf("https://api.credly.com/v1/organizations/%s/badge_templates/%s", c.OrganizationId, templateId)

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return b, err
}

resp, err := c.Do(req)
if err != nil {
return b, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return b, fmt.Errorf("[credly.GetBadgeTemplate] API request failed with status code: %d", resp.StatusCode)
}

var badgeResp getBadgeTemplateResponse
if err := json.NewDecoder(resp.Body).Decode(&badgeResp); err != nil {
return b, fmt.Errorf("[credly.GetBadgeTemplate] Failed to parse JSON data: %v", err)
}

return badgeResp.Data, nil
}

// GetBadgeTemplates retrieves all badge templates for the organization.
//
// Returns: A slice of BadgeTemplate representing all templates, or an error if the operation fails.
func (c *Client) GetBadgeTemplates() (b []BadgeTemplate, err error) {
url := fmt.Sprintf("https://api.credly.com/v1/organizations/%s/badge_templates", c.OrganizationId)

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return b, err
}

resp, err := c.Do(req)
if err != nil {
return b, err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return b, fmt.Errorf("[credly.GetBadgeTemplates] API request failed with status code: %d", resp.StatusCode)
}

var badgeResp getBadgeTemplatesResponse
if err := json.NewDecoder(resp.Body).Decode(&badgeResp); err != nil {
return b, fmt.Errorf("[credly.GetBadgeTemplates] Failed to parse JSON data: %v", err)
}

return badgeResp.Data, nil
}
Loading

0 comments on commit ca986b4

Please sign in to comment.