diff --git a/clients/go/holidays/holidays.go b/clients/go/holidays/holidays.go new file mode 100755 index 0000000..f8b2a63 --- /dev/null +++ b/clients/go/holidays/holidays.go @@ -0,0 +1,69 @@ +package holidays + +import ( + "github.com/m3o/m3o-go/client" +) + +func NewHolidaysService(token string) *HolidaysService { + return &HolidaysService{ + client: client.NewClient(&client.Options{ + Token: token, + }), + } +} + +type HolidaysService struct { + client *client.Client +} + +// +func (t *HolidaysService) Countries(request *CountriesRequest) (*CountriesResponse, error) { + rsp := &CountriesResponse{} + return rsp, t.client.Call("holidays", "Countries", request, rsp) +} + +// +func (t *HolidaysService) List(request *ListRequest) (*ListResponse, error) { + rsp := &ListResponse{} + return rsp, t.client.Call("holidays", "List", request, rsp) +} + +type CountriesRequest struct { +} + +type CountriesResponse struct { + Countries []Country `json:"countries"` +} + +type Country struct { + // The 2 letter country code (as defined in ISO 3166-1 alpha-2) + Code string `json:"code"` + // The English name of the country + Name string `json:"name"` +} + +type Holiday struct { + // the country this holiday occurs in + CountryCode string `json:"countryCode"` + // date of the holiday in yyyy-mm-dd format + Date string `json:"date"` + // the local name of the holiday + LocalName string `json:"localName"` + // the name of the holiday in English + Name string `json:"name"` + // the regions within the country that observe this holiday (if not all of them) + Regions []string `json:"regions"` + // the type of holiday Public, Bank, School, Authorities, Optional, Observance + Types []string `json:"types"` +} + +type ListRequest struct { + // The 2 letter country code (as defined in ISO 3166-1 alpha-2) + CountryCode string `json:"countryCode"` + // The year to list holidays for + Year int64 `json:"year"` +} + +type ListResponse struct { + Holidays []Holiday `json:"holidays"` +} diff --git a/clients/go/m3o.go b/clients/go/m3o.go index 39e91eb..6d8f4ae 100755 --- a/clients/go/m3o.go +++ b/clients/go/m3o.go @@ -13,6 +13,7 @@ import ( "github.com/micro/services/clients/go/forex" "github.com/micro/services/clients/go/geocoding" "github.com/micro/services/clients/go/helloworld" + "github.com/micro/services/clients/go/holidays" "github.com/micro/services/clients/go/id" "github.com/micro/services/clients/go/image" "github.com/micro/services/clients/go/ip" @@ -52,6 +53,7 @@ func NewClient(token string) *Client { ForexService: forex.NewForexService(token), GeocodingService: geocoding.NewGeocodingService(token), HelloworldService: helloworld.NewHelloworldService(token), + HolidaysService: holidays.NewHolidaysService(token), IdService: id.NewIdService(token), ImageService: image.NewImageService(token), IpService: ip.NewIpService(token), @@ -91,6 +93,7 @@ type Client struct { ForexService *forex.ForexService GeocodingService *geocoding.GeocodingService HelloworldService *helloworld.HelloworldService + HolidaysService *holidays.HolidaysService IdService *id.IdService ImageService *image.ImageService IpService *ip.IpService diff --git a/clients/go/quran/quran.go b/clients/go/quran/quran.go index a3f3428..2c1481b 100755 --- a/clients/go/quran/quran.go +++ b/clients/go/quran/quran.go @@ -87,7 +87,7 @@ type Result struct { // The associated arabic text Text string `json:"text"` // The related translations to the text - Translations []Translation `json:"translations"` + Translations []Interpretation `json:"translations"` // The unique verse id across the Quran VerseId int32 `json:"verseId"` // The verse key e.g 1:1 @@ -161,7 +161,7 @@ type Verse struct { // The basic translation of the verse TranslatedText string `json:"translatedText"` // The alternative translations for the verse - Translations []Translation `json:"translations"` + Translations []Interpretation `json:"translations"` // The phonetic transliteration from arabic Transliteration string `json:"transliteration"` // The individual words within the verse (Ayah) diff --git a/clients/ts/holidays/index.ts b/clients/ts/holidays/index.ts new file mode 100755 index 0000000..e25984f --- /dev/null +++ b/clients/ts/holidays/index.ts @@ -0,0 +1,64 @@ +import * as m3o from "@m3o/m3o-node"; + +export class HolidaysService { + private client: m3o.Client; + + constructor(token: string) { + this.client = new m3o.Client({ token: token }); + } + // + countries(request: CountriesRequest): Promise { + return this.client.call( + "holidays", + "Countries", + request + ) as Promise; + } + // + list(request: ListRequest): Promise { + return this.client.call( + "holidays", + "List", + request + ) as Promise; + } +} + +export interface CountriesRequest {} + +export interface CountriesResponse { + countries?: Country[]; +} + +export interface Country { + // The 2 letter country code (as defined in ISO 3166-1 alpha-2) + code?: string; + // The English name of the country + name?: string; +} + +export interface Holiday { + // the country this holiday occurs in + countryCode?: string; + // date of the holiday in yyyy-mm-dd format + date?: string; + // the local name of the holiday + localName?: string; + // the name of the holiday in English + name?: string; + // the regions within the country that observe this holiday (if not all of them) + regions?: string[]; + // the type of holiday Public, Bank, School, Authorities, Optional, Observance + types?: string[]; +} + +export interface ListRequest { + // The 2 letter country code (as defined in ISO 3166-1 alpha-2) + countryCode?: string; + // The year to list holidays for + year?: number; +} + +export interface ListResponse { + holidays?: Holiday[]; +} diff --git a/clients/ts/index.ts b/clients/ts/index.ts index 5ed6804..34c8246 100755 --- a/clients/ts/index.ts +++ b/clients/ts/index.ts @@ -10,6 +10,7 @@ import * as file from "./file"; import * as forex from "./forex"; import * as geocoding from "./geocoding"; import * as helloworld from "./helloworld"; +import * as holidays from "./holidays"; import * as id from "./id"; import * as image from "./image"; import * as ip from "./ip"; @@ -46,6 +47,7 @@ export class Client { this.forexService = new forex.ForexService(token); this.geocodingService = new geocoding.GeocodingService(token); this.helloworldService = new helloworld.HelloworldService(token); + this.holidaysService = new holidays.HolidaysService(token); this.idService = new id.IdService(token); this.imageService = new image.ImageService(token); this.ipService = new ip.IpService(token); @@ -81,6 +83,7 @@ export class Client { forexService: forex.ForexService; geocodingService: geocoding.GeocodingService; helloworldService: helloworld.HelloworldService; + holidaysService: holidays.HolidaysService; idService: id.IdService; imageService: image.ImageService; ipService: ip.IpService; diff --git a/clients/ts/package.json b/clients/ts/package.json index b1df120..0c49311 100644 --- a/clients/ts/package.json +++ b/clients/ts/package.json @@ -21,6 +21,7 @@ "./forex": "./dist/forex/index.js", "./geocoding": "./dist/geocoding/index.js", "./helloworld": "./dist/helloworld/index.js", + "./holidays": "./dist/holidays/index.js", "./id": "./dist/id/index.js", "./image": "./dist/image/index.js", "./ip": "./dist/ip/index.js", @@ -59,5 +60,5 @@ }, "type": "module", "types": "dist/index.d.ts", - "version": "1.0.521" + "version": "1.0.522" } \ No newline at end of file diff --git a/clients/ts/quran/index.ts b/clients/ts/quran/index.ts index 0371e68..f903ecc 100755 --- a/clients/ts/quran/index.ts +++ b/clients/ts/quran/index.ts @@ -87,7 +87,7 @@ export interface Result { // The associated arabic text text?: string; // The related translations to the text - translations?: Translation[]; + translations?: Interpretation[]; // The unique verse id across the Quran verseId?: number; // The verse key e.g 1:1 @@ -149,7 +149,7 @@ export interface Verse { // The unique id of the verse in the whole book id?: number; // The interpretations of the verse - interpretations?: Translation[]; + interpretations?: Interpretation[]; // The key of this verse (chapter:verse) e.g 1:1 key?: string; // The verse number in this chapter @@ -161,7 +161,7 @@ export interface Verse { // The basic translation of the verse translatedText?: string; // The alternative translations for the verse - translations?: Translation[]; + translations?: Interpretation[]; // The phonetic transliteration from arabic transliteration?: string; // The individual words within the verse (Ayah) diff --git a/examples/holidays/countries/curl/listCountries.sh b/examples/holidays/countries/curl/listCountries.sh new file mode 100755 index 0000000..c0bdb96 --- /dev/null +++ b/examples/holidays/countries/curl/listCountries.sh @@ -0,0 +1,4 @@ +curl "https://api.m3o.com/v1/holidays/Countries" \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer $MICRO_API_TOKEN" \ +-d '{}' \ No newline at end of file diff --git a/examples/holidays/countries/go/listCountries.go b/examples/holidays/countries/go/listCountries.go new file mode 100755 index 0000000..fa6169a --- /dev/null +++ b/examples/holidays/countries/go/listCountries.go @@ -0,0 +1,14 @@ +package example + +import ( + "fmt" + "github.com/micro/services/clients/go/holidays" + "os" +) + +// +func ListCountries() { + holidaysService := holidays.NewHolidaysService(os.Getenv("MICRO_API_TOKEN")) + rsp, err := holidaysService.Countries(&holidays.CountriesRequest{}) + fmt.Println(rsp, err) +} diff --git a/examples/holidays/countries/node/listCountries.js b/examples/holidays/countries/node/listCountries.js new file mode 100755 index 0000000..82588c3 --- /dev/null +++ b/examples/holidays/countries/node/listCountries.js @@ -0,0 +1,12 @@ +import * as holidays from "m3o/holidays"; + +// +async function ListCountries() { + let holidaysService = new holidays.HolidaysService( + process.env.MICRO_API_TOKEN + ); + let rsp = await holidaysService.countries({}); + console.log(rsp); +} + +await ListCountries(); diff --git a/examples/holidays/list/curl/getHolidays.sh b/examples/holidays/list/curl/getHolidays.sh new file mode 100755 index 0000000..0fafdfe --- /dev/null +++ b/examples/holidays/list/curl/getHolidays.sh @@ -0,0 +1,7 @@ +curl "https://api.m3o.com/v1/holidays/List" \ +-H "Content-Type: application/json" \ +-H "Authorization: Bearer $MICRO_API_TOKEN" \ +-d '{ + "country_code": "GB", + "year": 2022 +}' \ No newline at end of file diff --git a/examples/holidays/list/go/getHolidays.go b/examples/holidays/list/go/getHolidays.go new file mode 100755 index 0000000..72707f2 --- /dev/null +++ b/examples/holidays/list/go/getHolidays.go @@ -0,0 +1,16 @@ +package example + +import ( + "fmt" + "github.com/micro/services/clients/go/holidays" + "os" +) + +// +func GetHolidays() { + holidaysService := holidays.NewHolidaysService(os.Getenv("MICRO_API_TOKEN")) + rsp, err := holidaysService.List(&holidays.ListRequest{ + Year: 2022, + }) + fmt.Println(rsp, err) +} diff --git a/examples/holidays/list/node/getHolidays.js b/examples/holidays/list/node/getHolidays.js new file mode 100755 index 0000000..7836aa1 --- /dev/null +++ b/examples/holidays/list/node/getHolidays.js @@ -0,0 +1,15 @@ +import * as holidays from "m3o/holidays"; + +// +async function GetHolidays() { + let holidaysService = new holidays.HolidaysService( + process.env.MICRO_API_TOKEN + ); + let rsp = await holidaysService.list({ + country_code: "GB", + year: 2022, + }); + console.log(rsp); +} + +await GetHolidays(); diff --git a/examples/stream/publish/go/publishAMessage.go b/examples/stream/publish/go/publishAMessage.go index 0f33eac..f7db1b0 100755 --- a/examples/stream/publish/go/publishAMessage.go +++ b/examples/stream/publish/go/publishAMessage.go @@ -11,9 +11,9 @@ func PublishAmessage() { streamService := stream.NewStreamService(os.Getenv("MICRO_API_TOKEN")) rsp, err := streamService.Publish(&stream.PublishRequest{ Message: map[string]interface{}{ + "type": "signup", "user": "john", "id": "1", - "type": "signup", }, Topic: "events", }) diff --git a/go.sum b/go.sum index dc36d76..4f6fc98 100644 --- a/go.sum +++ b/go.sum @@ -693,6 +693,7 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= diff --git a/holidays/.gitignore b/holidays/.gitignore new file mode 100644 index 0000000..ca2758a --- /dev/null +++ b/holidays/.gitignore @@ -0,0 +1,2 @@ + +holidays diff --git a/holidays/Dockerfile b/holidays/Dockerfile new file mode 100644 index 0000000..9e9c670 --- /dev/null +++ b/holidays/Dockerfile @@ -0,0 +1,3 @@ +FROM alpine +ADD holidays /holidays +ENTRYPOINT [ "/holidays" ] diff --git a/holidays/Makefile b/holidays/Makefile new file mode 100644 index 0000000..5d5eb72 --- /dev/null +++ b/holidays/Makefile @@ -0,0 +1,28 @@ + +GOPATH:=$(shell go env GOPATH) +.PHONY: init +init: + go get -u github.com/golang/protobuf/proto + go get -u github.com/golang/protobuf/protoc-gen-go + go get github.com/micro/micro/v3/cmd/protoc-gen-micro + go get github.com/micro/micro/v3/cmd/protoc-gen-openapi + +.PHONY: api +api: + protoc --openapi_out=. --proto_path=. proto/holidays.proto + +.PHONY: proto +proto: + protoc --proto_path=. --micro_out=. --go_out=:. proto/holidays.proto + +.PHONY: build +build: + go build -o holidays *.go + +.PHONY: test +test: + go test -v ./... -cover + +.PHONY: docker +docker: + docker build . -t holidays:latest diff --git a/holidays/README.md b/holidays/README.md new file mode 100644 index 0000000..a4d870b --- /dev/null +++ b/holidays/README.md @@ -0,0 +1,15 @@ +Find the holidays observed in a particular country + +# Holidays Service + +List holidays observed in a country. Holidays may be at the country or region level. + +Holiday types are: +- Public - public holiday +- Bank - banks and offices are closed +- School - schools are closed +- Authorities - Government or other authorities are closed +- Optional - A day where a majority of people take the day off +- Observance - Optional day off, typically unpaid + +Powered by [Nager.Date](https://github.com/nager/Nager.Date/) diff --git a/holidays/examples.json b/holidays/examples.json new file mode 100644 index 0000000..bc328fe --- /dev/null +++ b/holidays/examples.json @@ -0,0 +1,647 @@ +{ + "countries": [{ + "title": "List countries", + "run_check": true, + "request": {}, + "response": { + "countries": [ + { + "code": "AD", + "name": "Andorra" + }, + { + "code": "AL", + "name": "Albania" + }, + { + "code": "AR", + "name": "Argentina" + }, + { + "code": "AT", + "name": "Austria" + }, + { + "code": "AU", + "name": "Australia" + }, + { + "code": "AX", + "name": "Åland Islands" + }, + { + "code": "BA", + "name": "Bosnia and Herzegovina" + }, + { + "code": "BB", + "name": "Barbados" + }, + { + "code": "BE", + "name": "Belgium" + }, + { + "code": "BG", + "name": "Bulgaria" + }, + { + "code": "BJ", + "name": "Benin" + }, + { + "code": "BO", + "name": "Bolivia" + }, + { + "code": "BR", + "name": "Brazil" + }, + { + "code": "BS", + "name": "Bahamas" + }, + { + "code": "BW", + "name": "Botswana" + }, + { + "code": "BY", + "name": "Belarus" + }, + { + "code": "BZ", + "name": "Belize" + }, + { + "code": "CA", + "name": "Canada" + }, + { + "code": "CH", + "name": "Switzerland" + }, + { + "code": "CL", + "name": "Chile" + }, + { + "code": "CN", + "name": "China" + }, + { + "code": "CO", + "name": "Colombia" + }, + { + "code": "CR", + "name": "Costa Rica" + }, + { + "code": "CU", + "name": "Cuba" + }, + { + "code": "CY", + "name": "Cyprus" + }, + { + "code": "CZ", + "name": "Czechia" + }, + { + "code": "DE", + "name": "Germany" + }, + { + "code": "DK", + "name": "Denmark" + }, + { + "code": "DO", + "name": "Dominican Republic" + }, + { + "code": "EC", + "name": "Ecuador" + }, + { + "code": "EE", + "name": "Estonia" + }, + { + "code": "EG", + "name": "Egypt" + }, + { + "code": "ES", + "name": "Spain" + }, + { + "code": "FI", + "name": "Finland" + }, + { + "code": "FO", + "name": "Faroe Islands" + }, + { + "code": "FR", + "name": "France" + }, + { + "code": "GA", + "name": "Gabon" + }, + { + "code": "GB", + "name": "United Kingdom" + }, + { + "code": "GD", + "name": "Grenada" + }, + { + "code": "GG", + "name": "Guernsey" + }, + { + "code": "GI", + "name": "Gibraltar" + }, + { + "code": "GL", + "name": "Greenland" + }, + { + "code": "GM", + "name": "Gambia" + }, + { + "code": "GR", + "name": "Greece" + }, + { + "code": "GT", + "name": "Guatemala" + }, + { + "code": "GY", + "name": "Guyana" + }, + { + "code": "HN", + "name": "Honduras" + }, + { + "code": "HR", + "name": "Croatia" + }, + { + "code": "HT", + "name": "Haiti" + }, + { + "code": "HU", + "name": "Hungary" + }, + { + "code": "ID", + "name": "Indonesia" + }, + { + "code": "IE", + "name": "Ireland" + }, + { + "code": "IM", + "name": "Isle of Man" + }, + { + "code": "IS", + "name": "Iceland" + }, + { + "code": "IT", + "name": "Italy" + }, + { + "code": "JE", + "name": "Jersey" + }, + { + "code": "JM", + "name": "Jamaica" + }, + { + "code": "JP", + "name": "Japan" + }, + { + "code": "KR", + "name": "South Korea" + }, + { + "code": "LI", + "name": "Liechtenstein" + }, + { + "code": "LS", + "name": "Lesotho" + }, + { + "code": "LT", + "name": "Lithuania" + }, + { + "code": "LU", + "name": "Luxembourg" + }, + { + "code": "LV", + "name": "Latvia" + }, + { + "code": "MA", + "name": "Morocco" + }, + { + "code": "MC", + "name": "Monaco" + }, + { + "code": "MD", + "name": "Moldova" + }, + { + "code": "ME", + "name": "Montenegro" + }, + { + "code": "MG", + "name": "Madagascar" + }, + { + "code": "MK", + "name": "North Macedonia" + }, + { + "code": "MN", + "name": "Mongolia" + }, + { + "code": "MS", + "name": "Montserrat" + }, + { + "code": "MT", + "name": "Malta" + }, + { + "code": "MX", + "name": "Mexico" + }, + { + "code": "MZ", + "name": "Mozambique" + }, + { + "code": "NA", + "name": "Namibia" + }, + { + "code": "NE", + "name": "Niger" + }, + { + "code": "NG", + "name": "Nigeria" + }, + { + "code": "NI", + "name": "Nicaragua" + }, + { + "code": "NL", + "name": "Netherlands" + }, + { + "code": "NO", + "name": "Norway" + }, + { + "code": "NZ", + "name": "New Zealand" + }, + { + "code": "PA", + "name": "Panama" + }, + { + "code": "PE", + "name": "Peru" + }, + { + "code": "PG", + "name": "Papua New Guinea" + }, + { + "code": "PL", + "name": "Poland" + }, + { + "code": "PR", + "name": "Puerto Rico" + }, + { + "code": "PT", + "name": "Portugal" + }, + { + "code": "PY", + "name": "Paraguay" + }, + { + "code": "RO", + "name": "Romania" + }, + { + "code": "RS", + "name": "Serbia" + }, + { + "code": "RU", + "name": "Russia" + }, + { + "code": "SE", + "name": "Sweden" + }, + { + "code": "SG", + "name": "Singapore" + }, + { + "code": "SI", + "name": "Slovenia" + }, + { + "code": "SJ", + "name": "Svalbard and Jan Mayen" + }, + { + "code": "SK", + "name": "Slovakia" + }, + { + "code": "SM", + "name": "San Marino" + }, + { + "code": "SR", + "name": "Suriname" + }, + { + "code": "SV", + "name": "El Salvador" + }, + { + "code": "TN", + "name": "Tunisia" + }, + { + "code": "TR", + "name": "Turkey" + }, + { + "code": "UA", + "name": "Ukraine" + }, + { + "code": "US", + "name": "United States" + }, + { + "code": "UY", + "name": "Uruguay" + }, + { + "code": "VA", + "name": "Vatican City" + }, + { + "code": "VE", + "name": "Venezuela" + }, + { + "code": "VN", + "name": "Vietnam" + }, + { + "code": "ZA", + "name": "South Africa" + }, + { + "code": "ZW", + "name": "Zimbabwe" + } + ] + } + }], + "list": [ + { + "title": "Get holidays", + "run_check": true, + "request": {"country_code": "GB", "year": 2022}, + "response": { + "holidays": [ + { + "date": "2022-01-01", + "name": "New Year's Day", + "local_name": "New Year's Day", + "country_code": "GB", + "regions": [ + "GB-NIR" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-01-03", + "name": "New Year's Day", + "local_name": "New Year's Day", + "country_code": "GB", + "regions": [ + "GB-ENG", + "GB-WLS" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-01-03", + "name": "New Year's Day", + "local_name": "New Year's Day", + "country_code": "GB", + "regions": [ + "GB-SCT" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-01-04", + "name": "New Year's Day", + "local_name": "New Year's Day", + "country_code": "GB", + "regions": [ + "GB-SCT" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-03-17", + "name": "Saint Patrick's Day", + "local_name": "Saint Patrick's Day", + "country_code": "GB", + "regions": [ + "GB-NIR" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-04-15", + "name": "Good Friday", + "local_name": "Good Friday", + "country_code": "GB", + "regions": [], + "types": [ + "Public" + ] + }, + { + "date": "2022-04-18", + "name": "Easter Monday", + "local_name": "Easter Monday", + "country_code": "GB", + "regions": [ + "GB-ENG", + "GB-WLS", + "GB-NIR" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-05-02", + "name": "Early May Bank Holiday", + "local_name": "Early May Bank Holiday", + "country_code": "GB", + "regions": [], + "types": [ + "Public" + ] + }, + { + "date": "2022-06-02", + "name": "Spring Bank Holiday", + "local_name": "Spring Bank Holiday", + "country_code": "GB", + "regions": [], + "types": [ + "Public" + ] + }, + { + "date": "2022-06-03", + "name": "Queen’s Platinum Jubilee", + "local_name": "Queen’s Platinum Jubilee", + "country_code": "GB", + "regions": [], + "types": [ + "Public" + ] + }, + { + "date": "2022-07-12", + "name": "Battle of the Boyne", + "local_name": "Battle of the Boyne", + "country_code": "GB", + "regions": [ + "GB-NIR" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-08-01", + "name": "Summer Bank Holiday", + "local_name": "Summer Bank Holiday", + "country_code": "GB", + "regions": [ + "GB-SCT" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-08-29", + "name": "Summer Bank Holiday", + "local_name": "Summer Bank Holiday", + "country_code": "GB", + "regions": [ + "GB-ENG", + "GB-WLS", + "GB-NIR" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-11-30", + "name": "Saint Andrew's Day", + "local_name": "Saint Andrew's Day", + "country_code": "GB", + "regions": [ + "GB-SCT" + ], + "types": [ + "Public" + ] + }, + { + "date": "2022-12-26", + "name": "St. Stephen's Day", + "local_name": "Boxing Day", + "country_code": "GB", + "regions": [], + "types": [ + "Public" + ] + }, + { + "date": "2022-12-27", + "name": "Christmas Day", + "local_name": "Christmas Day", + "country_code": "GB", + "regions": [], + "types": [ + "Public" + ] + } + ] + } + } + ] +} diff --git a/holidays/generate.go b/holidays/generate.go new file mode 100644 index 0000000..96f431a --- /dev/null +++ b/holidays/generate.go @@ -0,0 +1,2 @@ +package main +//go:generate make proto diff --git a/holidays/handler/holidays.go b/holidays/handler/holidays.go new file mode 100644 index 0000000..5982481 --- /dev/null +++ b/holidays/handler/holidays.go @@ -0,0 +1,126 @@ +package handler + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + "github.com/micro/micro/v3/service/config" + "github.com/micro/micro/v3/service/errors" + log "github.com/micro/micro/v3/service/logger" + + pb "github.com/micro/services/holidays/proto" +) + +type Holidays struct { + conf conf +} + +type conf struct { + NagerHost string `json:"nager_host"` +} + +func New() *Holidays { + val, err := config.Get("micro.holidays") + if err != nil { + log.Fatalf("Failed to load config %s", err) + } + var conf conf + if err := val.Scan(&conf); err != nil { + log.Fatalf("Failed to load config %s", err) + } + if len(conf.NagerHost) == 0 { + log.Fatalf("Nager host not configured") + } + return &Holidays{conf: conf} +} + +type nagerCountry struct { + CountryCode string `json:"countryCode"` + Name string `json:"name"` +} + +func (h *Holidays) Countries(ctx context.Context, request *pb.CountriesRequest, response *pb.CountriesResponse) error { + rsp, err := http.Get(h.conf.NagerHost + "/api/v3/AvailableCountries") + if err != nil { + log.Errorf("Error listing available countries %s", err) + return errors.InternalServerError("holidays.countries", "Error retrieving country list") + } + defer rsp.Body.Close() + if rsp.StatusCode != 200 { + log.Errorf("Error listing available countries %s", rsp.Status) + return errors.InternalServerError("holidays.countries", "Error retrieving country list") + } + b, err := ioutil.ReadAll(rsp.Body) + if err != nil { + log.Errorf("Error processing available countries %s", err) + return errors.InternalServerError("holidays.countries", "Error retrieving country list") + } + var rspArr []nagerCountry + if err := json.Unmarshal(b, &rspArr); err != nil { + log.Errorf("Error processing available countries %s", err) + return errors.InternalServerError("holidays.countries", "Error retrieving country list") + } + response.Countries = make([]*pb.Country, len(rspArr)) + for i, c := range rspArr { + response.Countries[i] = &pb.Country{ + Code: c.CountryCode, + Name: c.Name, + } + } + return nil +} + +type nagerHoliday struct { + Date string `json:"date"` + LocalName string `json:"localName"` + Name string `json:"name"` + CountryCode string `json:"countryCode"` + Counties []string `json:"counties"` + Types []string `json:"types"` +} + +func (h Holidays) List(ctx context.Context, request *pb.ListRequest, response *pb.ListResponse) error { + if request.Year == 0 { + return errors.BadRequest("holidays.list", "Missing year argument") + } + if len(request.CountryCode) == 0 { + return errors.BadRequest("holidays.list", "Missing country code argument") + } + rsp, err := http.Get(fmt.Sprintf("%s/api/v3/PublicHolidays/%d/%s", h.conf.NagerHost, request.Year, request.CountryCode)) + if err != nil { + log.Errorf("Error listing available countries %s", err) + return errors.InternalServerError("holidays.list", "Error retrieving holidays list") + } + defer rsp.Body.Close() + if rsp.StatusCode != 200 { + log.Errorf("Error listing holidays %s", rsp.Status) + return errors.InternalServerError("holidays.list", "Error retrieving holidays list") + } + b, err := ioutil.ReadAll(rsp.Body) + if err != nil { + log.Errorf("Error processing holidays %s", err) + return errors.InternalServerError("holidays.countries", "Error retrieving holidays list") + } + var rspArr []nagerHoliday + if err := json.Unmarshal(b, &rspArr); err != nil { + log.Errorf("Error processing holidays %s", err) + return errors.InternalServerError("holidays.countries", "Error retrieving holidays list") + } + + response.Holidays = make([]*pb.Holiday, len(rspArr)) + for i, c := range rspArr { + response.Holidays[i] = &pb.Holiday{ + Date: c.Date, + Name: c.Name, + LocalName: c.LocalName, + CountryCode: c.CountryCode, + Regions: c.Counties, + Types: c.Types, + } + } + + return nil +} diff --git a/holidays/main.go b/holidays/main.go new file mode 100644 index 0000000..a175edf --- /dev/null +++ b/holidays/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "github.com/micro/services/holidays/handler" + pb "github.com/micro/services/holidays/proto" + + "github.com/micro/micro/v3/service" + "github.com/micro/micro/v3/service/logger" +) + +func main() { + // Create service + srv := service.New( + service.Name("holidays"), + service.Version("latest"), + ) + + // Register handler + pb.RegisterHolidaysHandler(srv.Server(), handler.New()) + + // Run service + if err := srv.Run(); err != nil { + logger.Fatal(err) + } +} diff --git a/holidays/micro.mu b/holidays/micro.mu new file mode 100644 index 0000000..fe4d6b0 --- /dev/null +++ b/holidays/micro.mu @@ -0,0 +1 @@ +service holidays diff --git a/holidays/nager-k8s.yaml b/holidays/nager-k8s.yaml new file mode 100644 index 0000000..7dc30d8 --- /dev/null +++ b/holidays/nager-k8s.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nager-latest + labels: + app: nager +spec: + replicas: 2 + selector: + matchLabels: + app: nager + template: + metadata: + labels: + app: nager + spec: + containers: + - name: nager + image: nager/nager-date:latest + ports: + - containerPort: 80 + env: + - name: EnableCors + value: "true" + - name: EnableIpRateLimiting + value: "false" + +--- + +apiVersion: v1 +kind: Service +metadata: + name: nager +spec: + selector: + app: nager + ports: + - protocol: TCP + port: 80 + targetPort: 80 diff --git a/holidays/proto/holidays.pb.go b/holidays/proto/holidays.pb.go new file mode 100644 index 0000000..185755b --- /dev/null +++ b/holidays/proto/holidays.pb.go @@ -0,0 +1,540 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.15.5 +// source: proto/holidays.proto + +package holidays + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CountriesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CountriesRequest) Reset() { + *x = CountriesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_holidays_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CountriesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CountriesRequest) ProtoMessage() {} + +func (x *CountriesRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_holidays_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CountriesRequest.ProtoReflect.Descriptor instead. +func (*CountriesRequest) Descriptor() ([]byte, []int) { + return file_proto_holidays_proto_rawDescGZIP(), []int{0} +} + +type CountriesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Countries []*Country `protobuf:"bytes,1,rep,name=countries,proto3" json:"countries,omitempty"` +} + +func (x *CountriesResponse) Reset() { + *x = CountriesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_holidays_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CountriesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CountriesResponse) ProtoMessage() {} + +func (x *CountriesResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_holidays_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CountriesResponse.ProtoReflect.Descriptor instead. +func (*CountriesResponse) Descriptor() ([]byte, []int) { + return file_proto_holidays_proto_rawDescGZIP(), []int{1} +} + +func (x *CountriesResponse) GetCountries() []*Country { + if x != nil { + return x.Countries + } + return nil +} + +type Country struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The 2 letter country code (as defined in ISO 3166-1 alpha-2) + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` + // The English name of the country + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *Country) Reset() { + *x = Country{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_holidays_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Country) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Country) ProtoMessage() {} + +func (x *Country) ProtoReflect() protoreflect.Message { + mi := &file_proto_holidays_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Country.ProtoReflect.Descriptor instead. +func (*Country) Descriptor() ([]byte, []int) { + return file_proto_holidays_proto_rawDescGZIP(), []int{2} +} + +func (x *Country) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *Country) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type ListRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The 2 letter country code (as defined in ISO 3166-1 alpha-2) + CountryCode string `protobuf:"bytes,1,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"` + // The year to list holidays for + Year int64 `protobuf:"varint,2,opt,name=year,proto3" json:"year,omitempty"` +} + +func (x *ListRequest) Reset() { + *x = ListRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_holidays_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListRequest) ProtoMessage() {} + +func (x *ListRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_holidays_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListRequest.ProtoReflect.Descriptor instead. +func (*ListRequest) Descriptor() ([]byte, []int) { + return file_proto_holidays_proto_rawDescGZIP(), []int{3} +} + +func (x *ListRequest) GetCountryCode() string { + if x != nil { + return x.CountryCode + } + return "" +} + +func (x *ListRequest) GetYear() int64 { + if x != nil { + return x.Year + } + return 0 +} + +type ListResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Holidays []*Holiday `protobuf:"bytes,1,rep,name=holidays,proto3" json:"holidays,omitempty"` +} + +func (x *ListResponse) Reset() { + *x = ListResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_holidays_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListResponse) ProtoMessage() {} + +func (x *ListResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_holidays_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListResponse.ProtoReflect.Descriptor instead. +func (*ListResponse) Descriptor() ([]byte, []int) { + return file_proto_holidays_proto_rawDescGZIP(), []int{4} +} + +func (x *ListResponse) GetHolidays() []*Holiday { + if x != nil { + return x.Holidays + } + return nil +} + +type Holiday struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // date of the holiday in yyyy-mm-dd format + Date string `protobuf:"bytes,1,opt,name=date,proto3" json:"date,omitempty"` + // the name of the holiday in English + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // the local name of the holiday + LocalName string `protobuf:"bytes,3,opt,name=local_name,json=localName,proto3" json:"local_name,omitempty"` + // the country this holiday occurs in + CountryCode string `protobuf:"bytes,4,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"` + // the regions within the country that observe this holiday (if not all of them) + Regions []string `protobuf:"bytes,5,rep,name=regions,proto3" json:"regions,omitempty"` + // the type of holiday Public, Bank, School, Authorities, Optional, Observance + Types []string `protobuf:"bytes,6,rep,name=types,proto3" json:"types,omitempty"` +} + +func (x *Holiday) Reset() { + *x = Holiday{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_holidays_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Holiday) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Holiday) ProtoMessage() {} + +func (x *Holiday) ProtoReflect() protoreflect.Message { + mi := &file_proto_holidays_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Holiday.ProtoReflect.Descriptor instead. +func (*Holiday) Descriptor() ([]byte, []int) { + return file_proto_holidays_proto_rawDescGZIP(), []int{5} +} + +func (x *Holiday) GetDate() string { + if x != nil { + return x.Date + } + return "" +} + +func (x *Holiday) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Holiday) GetLocalName() string { + if x != nil { + return x.LocalName + } + return "" +} + +func (x *Holiday) GetCountryCode() string { + if x != nil { + return x.CountryCode + } + return "" +} + +func (x *Holiday) GetRegions() []string { + if x != nil { + return x.Regions + } + return nil +} + +func (x *Holiday) GetTypes() []string { + if x != nil { + return x.Types + } + return nil +} + +var File_proto_holidays_proto protoreflect.FileDescriptor + +var file_proto_holidays_proto_rawDesc = []byte{ + 0x0a, 0x14, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x68, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, + 0x22, 0x12, 0x0a, 0x10, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x22, 0x44, 0x0a, 0x11, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x68, + 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x31, 0x0a, 0x07, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x44, 0x0a, + 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x79, 0x65, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x79, + 0x65, 0x61, 0x72, 0x22, 0x3d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x68, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x68, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, + 0x2e, 0x48, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x52, 0x08, 0x68, 0x6f, 0x6c, 0x69, 0x64, 0x61, + 0x79, 0x73, 0x22, 0xa3, 0x01, 0x0a, 0x07, 0x48, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, + 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x6f, 0x63, 0x61, + 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, + 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x67, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x32, 0x8b, 0x01, 0x0a, 0x08, 0x48, 0x6f, 0x6c, + 0x69, 0x64, 0x61, 0x79, 0x73, 0x12, 0x46, 0x0a, 0x09, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x69, + 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x68, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, 0x2e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, + 0x2e, 0x68, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, + 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, + 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x15, 0x2e, 0x68, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, + 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x12, 0x5a, 0x10, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x3b, 0x68, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_proto_holidays_proto_rawDescOnce sync.Once + file_proto_holidays_proto_rawDescData = file_proto_holidays_proto_rawDesc +) + +func file_proto_holidays_proto_rawDescGZIP() []byte { + file_proto_holidays_proto_rawDescOnce.Do(func() { + file_proto_holidays_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_holidays_proto_rawDescData) + }) + return file_proto_holidays_proto_rawDescData +} + +var file_proto_holidays_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_proto_holidays_proto_goTypes = []interface{}{ + (*CountriesRequest)(nil), // 0: holidays.CountriesRequest + (*CountriesResponse)(nil), // 1: holidays.CountriesResponse + (*Country)(nil), // 2: holidays.Country + (*ListRequest)(nil), // 3: holidays.ListRequest + (*ListResponse)(nil), // 4: holidays.ListResponse + (*Holiday)(nil), // 5: holidays.Holiday +} +var file_proto_holidays_proto_depIdxs = []int32{ + 2, // 0: holidays.CountriesResponse.countries:type_name -> holidays.Country + 5, // 1: holidays.ListResponse.holidays:type_name -> holidays.Holiday + 0, // 2: holidays.Holidays.Countries:input_type -> holidays.CountriesRequest + 3, // 3: holidays.Holidays.List:input_type -> holidays.ListRequest + 1, // 4: holidays.Holidays.Countries:output_type -> holidays.CountriesResponse + 4, // 5: holidays.Holidays.List:output_type -> holidays.ListResponse + 4, // [4:6] is the sub-list for method output_type + 2, // [2:4] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_proto_holidays_proto_init() } +func file_proto_holidays_proto_init() { + if File_proto_holidays_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_proto_holidays_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CountriesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_holidays_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CountriesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_holidays_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Country); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_holidays_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_holidays_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_holidays_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Holiday); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proto_holidays_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_proto_holidays_proto_goTypes, + DependencyIndexes: file_proto_holidays_proto_depIdxs, + MessageInfos: file_proto_holidays_proto_msgTypes, + }.Build() + File_proto_holidays_proto = out.File + file_proto_holidays_proto_rawDesc = nil + file_proto_holidays_proto_goTypes = nil + file_proto_holidays_proto_depIdxs = nil +} diff --git a/holidays/proto/holidays.pb.micro.go b/holidays/proto/holidays.pb.micro.go new file mode 100644 index 0000000..f10744c --- /dev/null +++ b/holidays/proto/holidays.pb.micro.go @@ -0,0 +1,114 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: proto/holidays.proto + +package holidays + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +import ( + context "context" + api "github.com/micro/micro/v3/service/api" + client "github.com/micro/micro/v3/service/client" + server "github.com/micro/micro/v3/service/server" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// Reference imports to suppress errors if they are not otherwise used. +var _ api.Endpoint +var _ context.Context +var _ client.Option +var _ server.Option + +// Api Endpoints for Holidays service + +func NewHolidaysEndpoints() []*api.Endpoint { + return []*api.Endpoint{} +} + +// Client API for Holidays service + +type HolidaysService interface { + // Get the list of countries that are supported by this API + Countries(ctx context.Context, in *CountriesRequest, opts ...client.CallOption) (*CountriesResponse, error) + // List the holiday dates for a given country and year + List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) +} + +type holidaysService struct { + c client.Client + name string +} + +func NewHolidaysService(name string, c client.Client) HolidaysService { + return &holidaysService{ + c: c, + name: name, + } +} + +func (c *holidaysService) Countries(ctx context.Context, in *CountriesRequest, opts ...client.CallOption) (*CountriesResponse, error) { + req := c.c.NewRequest(c.name, "Holidays.Countries", in) + out := new(CountriesResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *holidaysService) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) { + req := c.c.NewRequest(c.name, "Holidays.List", in) + out := new(ListResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Holidays service + +type HolidaysHandler interface { + // Get the list of countries that are supported by this API + Countries(context.Context, *CountriesRequest, *CountriesResponse) error + // List the holiday dates for a given country and year + List(context.Context, *ListRequest, *ListResponse) error +} + +func RegisterHolidaysHandler(s server.Server, hdlr HolidaysHandler, opts ...server.HandlerOption) error { + type holidays interface { + Countries(ctx context.Context, in *CountriesRequest, out *CountriesResponse) error + List(ctx context.Context, in *ListRequest, out *ListResponse) error + } + type Holidays struct { + holidays + } + h := &holidaysHandler{hdlr} + return s.Handle(s.NewHandler(&Holidays{h}, opts...)) +} + +type holidaysHandler struct { + HolidaysHandler +} + +func (h *holidaysHandler) Countries(ctx context.Context, in *CountriesRequest, out *CountriesResponse) error { + return h.HolidaysHandler.Countries(ctx, in, out) +} + +func (h *holidaysHandler) List(ctx context.Context, in *ListRequest, out *ListResponse) error { + return h.HolidaysHandler.List(ctx, in, out) +} diff --git a/holidays/proto/holidays.proto b/holidays/proto/holidays.proto new file mode 100644 index 0000000..9eeeb9d --- /dev/null +++ b/holidays/proto/holidays.proto @@ -0,0 +1,52 @@ +syntax = "proto3"; + +package holidays; + +option go_package = "./proto;holidays"; + +service Holidays { + // Get the list of countries that are supported by this API + rpc Countries(CountriesRequest) returns (CountriesResponse) {} + // List the holiday dates for a given country and year + rpc List(ListRequest) returns (ListResponse) {} +} + +message CountriesRequest { +} + +message CountriesResponse { + repeated Country countries = 1; +} + +message Country { + // The 2 letter country code (as defined in ISO 3166-1 alpha-2) + string code = 1; + // The English name of the country + string name = 2; +} + +message ListRequest { + // The 2 letter country code (as defined in ISO 3166-1 alpha-2) + string country_code = 1; + // The year to list holidays for + int64 year = 2; +} + +message ListResponse { + repeated Holiday holidays = 1; +} + +message Holiday { + // date of the holiday in yyyy-mm-dd format + string date = 1; + // the name of the holiday in English + string name = 2; + // the local name of the holiday + string local_name = 3; + // the country this holiday occurs in + string country_code = 4; + // the regions within the country that observe this holiday (if not all of them) + repeated string regions = 5; + // the type of holiday Public, Bank, School, Authorities, Optional, Observance + repeated string types = 6; +} diff --git a/holidays/publicapi.json b/holidays/publicapi.json new file mode 100644 index 0000000..00d8c9c --- /dev/null +++ b/holidays/publicapi.json @@ -0,0 +1,5 @@ +{ + "name": "holidays", + "icon": "🏖️", + "category": "util" +}