Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #74

Merged
merged 4 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
- [Viper](https://github.com/spf13/viper)
- [gin-swagger](https://github.com/swaggo/gin-swagger) for generating docs

<hr>

## Getting started
1. Clone the repository
2. Go to the project's root directory
Expand All @@ -22,7 +24,7 @@
- `docker-compose up` to run the database container
- `make runserver` - to run HTTP server
5. Now everything should be ready and server running on `SERVER_ADDRESS` specified in `app.env`

<hr>

## Testing
1. Run the postgres container (`docker-compose up`)
Expand All @@ -32,15 +34,23 @@
- `make test_coverage p={PATH}` - to get the coverage in the HTML format - where `{PATH}` is the path to the target directory for which you want to generate test coverage. The `{PATH}` should be replaced with the actual path you want to use. For example `./api`
or
- use standard `go test` commands (e.g. `go test -v ./api`)

<hr>

## API endpoints
This API provides a set of endpoints for managing:
- users
- employers
- jobs

#### The base path for all endpoints is `/api/v1`.
After running the server, the Swagger documentation is available at http://localhost:8080/swagger/index.html.
You can find there detailed information about the API endpoints, including their parameters,
request and response formats, and examples. You can use the Swagger UI to test the API
endpoints and see their responses in real-time.

### The base path for all endpoints is `/api/v1`
so for example `/api/v1/users/login`


Here is a summary of the available endpoints and their functionality:


Expand Down
1 change: 1 addition & 0 deletions app.env.sample
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
DB_DRIVER=postgres
DB_SOURCE=based on docker-compose.yml -> postgresql://devuser:admin@localhost:5432/go_gin_job_search_db?sslmode=disable
SERVER_ADDRESS=for example 0.0.0.0:8080
ELASTICSEARCH_ADDRESS=for example http://localhost:9200
TOKEN_SYMMETRIC_KEY=32 characters long, you can use just 12345678901234567890123456789012
ACCESS_TOKEN_DURATION=for example 20m or 24h
30 changes: 30 additions & 0 deletions db/mock/store.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions db/queries/job.sql
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,16 @@ RETURNING *;
DELETE
FROM jobs
WHERE id = $1;

-- name: ListAllJobsForES :many
SELECT j.id,
j.title,
j.industry,
j.location,
j.description,
c.name AS company_name,
j.salary_min,
j.salary_max,
j.requirements
FROM jobs j
JOIN companies c ON j.company_id = c.id;
5 changes: 5 additions & 0 deletions db/queries/job_skill.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ FROM job_skills
WHERE job_id = $1
LIMIT $2 OFFSET $3;

-- name: ListAllJobSkillsByJobID :many
SELECT skill
FROM job_skills
WHERE job_id = $1;

-- name: ListJobsBySkill :many
SELECT job_id
FROM job_skills
Expand Down
59 changes: 59 additions & 0 deletions db/sqlc/job.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions db/sqlc/job_skill.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions db/sqlc/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,51 @@ services:
ports:
- "5432:5432"

elasticsearch:
container_name: go_gin_job_search_es
image: elasticsearch:7.17.9
environment:
- bootstrap.memory_lock=true
- ES_JAVA_OPTS=-Xms1g -Xmx1g
- cluster.name=job-search-esearch
- discovery.type=single-node
- node.name=job-search-es-node
ulimits:
memlock:
hard: -1
soft: -1
ports:
- "9200:9200"
networks:
- es-job-search
healthcheck:
interval: 10s
retries: 20
test: curl -s http://localhost:9200/_cluster/health | grep -vq '"status":"red"'
depends_on:
- db

kibana:
image: kibana:7.17.10
container_name: go_gin_job_search_kibana
depends_on:
elasticsearch:
condition: service_healthy
environment:
ELASTICSEARCH_URL: http://elasticsearch:9200
ELASTICSEARCH_HOSTS: http://elasticsearch:9200
ports:
- "5601:5601"
networks:
- es-job-search
healthcheck:
interval: 10s
retries: 20
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:5601/api/status

networks:
es-job-search:
driver: bridge

volumes:
dev-db-data:
21 changes: 21 additions & 0 deletions esearch/connect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package esearch

import (
"context"
"github.com/elastic/go-elasticsearch/v8"
)

// ConnectWithElasticsearch creates a new elasticsearch client and stores it in the context
func ConnectWithElasticsearch(ctx context.Context, address string) context.Context {

newClient, err := elasticsearch.NewClient(elasticsearch.Config{
Addresses: []string{
address,
},
})
if err != nil {
panic(err)
}

return context.WithValue(ctx, ClientKey, newClient)
}
75 changes: 75 additions & 0 deletions esearch/index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package esearch

import (
"bytes"
"context"
"io"
"log"
"strconv"

"github.com/elastic/go-elasticsearch/v8"
"github.com/elastic/go-elasticsearch/v8/esutil"
)

// IndexJobsAsDocuments index jobs as documents
func IndexJobsAsDocuments(ctx context.Context) {

jobs := ctx.Value(JobKey).([]Job)
client := ctx.Value(ClientKey).(*elasticsearch.Client)

bulkIndexer, err := esutil.NewBulkIndexer(esutil.BulkIndexerConfig{
Index: "jobs",
Client: client,
NumWorkers: 5,
})
if err != nil {
panic(err)
}

for documentID, document := range jobs {
body, err := readerToReadSeeker(esutil.NewJSONReader(document))
if err != nil {
panic(err)
}
err = bulkIndexer.Add(
ctx,
esutil.BulkIndexerItem{
Action: "index",
DocumentID: strconv.Itoa(documentID),
Body: body,
},
)
if err != nil {
panic(err)
}
}

bulkIndexer.Close(ctx)
biStats := bulkIndexer.Stats()
log.Printf("Jobs indexed on Elasticsearch: %d \n", biStats.NumIndexed)
}

// IndexJobAsDocument index one job as document
//func IndexJobAsDocument(ctx context.Context, job Job) {

//client := ctx.Value(ClientKey).(*elasticsearch.Client)

// get id of the last document and set documentID to it + 1
//_, err := client.Index("movies", esutil.NewJSONReader(job),
// client.Index.WithDocumentID(strconv.Itoa(documentID)))
//if err != nil {
// panic(err)
//}
//}

func readerToReadSeeker(reader io.Reader) (io.ReadSeeker, error) {
// Read the entire content of the reader into a buffer.
data, err := io.ReadAll(reader)
if err != nil {
return nil, err
}

// Create a new io.ReadSeeker from the buffer.
readSeeker := bytes.NewReader(data)
return readSeeker, nil
}
Loading