-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* wrappers to email and sms notifications via sendgrid and twilio * db methods and api endpoints for email verification * db and api tests * allowing to verify users with no code if email service is not defined (for testing) * new endpoints to request a password recovery and reset user password * api test for recover and reset password
- Loading branch information
1 parent
c11c238
commit b651ae1
Showing
33 changed files
with
1,216 additions
and
127 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ import ( | |
|
||
"github.com/vocdoni/saas-backend/account" | ||
"github.com/vocdoni/saas-backend/db" | ||
"github.com/vocdoni/saas-backend/notifications/testmail" | ||
"github.com/vocdoni/saas-backend/test" | ||
"go.vocdoni.io/dvote/apiclient" | ||
) | ||
|
@@ -24,17 +25,27 @@ type apiTestCase struct { | |
} | ||
|
||
const ( | ||
testSecret = "super-secret" | ||
testEmail = "[email protected]" | ||
testPass = "password123" | ||
testHost = "0.0.0.0" | ||
testPort = 7788 | ||
testSecret = "super-secret" | ||
testEmail = "[email protected]" | ||
testPass = "password123" | ||
testFirstName = "test" | ||
testLastName = "user" | ||
testHost = "0.0.0.0" | ||
testPort = 7788 | ||
|
||
adminEmail = "[email protected]" | ||
adminUser = "admin" | ||
adminPass = "admin123" | ||
) | ||
|
||
// testDB is the MongoDB storage for the tests. Make it global so it can be | ||
// accessed by the tests directly. | ||
var testDB *db.MongoStorage | ||
|
||
// testMailService is the test mail service for the tests. Make it global so it | ||
// can be accessed by the tests directly. | ||
var testMailService *testmail.TestMail | ||
|
||
// testURL helper function returns the full URL for the given path using the | ||
// test host and port. | ||
func testURL(path string) string { | ||
|
@@ -95,6 +106,13 @@ func TestMain(m *testing.M) { | |
if err != nil { | ||
panic(err) | ||
} | ||
// set reset db env var to true | ||
_ = os.Setenv("VOCDONI_MONGO_RESET_DB", "true") | ||
// create a new MongoDB connection with the test database | ||
if testDB, err = db.New(mongoURI, test.RandomDatabaseName()); err != nil { | ||
panic(err) | ||
} | ||
defer testDB.Close() | ||
// start the faucet container | ||
faucetContainer, err := test.StartVocfaucetContainer(ctx) | ||
if err != nil { | ||
|
@@ -113,13 +131,24 @@ func TestMain(m *testing.M) { | |
panic(err) | ||
} | ||
testAPIEndpoint := test.VoconedAPIURL(apiEndpoint) | ||
// set reset db env var to true | ||
_ = os.Setenv("VOCDONI_MONGO_RESET_DB", "true") | ||
// create a new MongoDB connection with the test database | ||
if testDB, err = db.New(mongoURI, test.RandomDatabaseName()); err != nil { | ||
// start test mail server | ||
testMailServer, err := test.StartMailService(ctx) | ||
if err != nil { | ||
panic(err) | ||
} | ||
// get the host, the SMTP port and the API port | ||
mailHost, err := testMailServer.Host(ctx) | ||
if err != nil { | ||
panic(err) | ||
} | ||
smtpPort, err := testMailServer.MappedPort(ctx, test.MailSMTPPort) | ||
if err != nil { | ||
panic(err) | ||
} | ||
apiPort, err := testMailServer.MappedPort(ctx, test.MailAPIPort) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer testDB.Close() | ||
// create the remote test API client | ||
testAPIClient, err := apiclient.New(testAPIEndpoint) | ||
if err != nil { | ||
|
@@ -131,6 +160,18 @@ func TestMain(m *testing.M) { | |
if err != nil { | ||
panic(err) | ||
} | ||
// create test mail service | ||
testMailService = new(testmail.TestMail) | ||
if err := testMailService.Init(&testmail.TestMailConfig{ | ||
FromAddress: adminEmail, | ||
SMTPUser: adminUser, | ||
SMTPPassword: adminPass, | ||
Host: mailHost, | ||
SMTPPort: smtpPort.Int(), | ||
APIPort: apiPort.Int(), | ||
}); err != nil { | ||
panic(err) | ||
} | ||
// start the API | ||
New(&APIConfig{ | ||
Host: testHost, | ||
|
@@ -139,6 +180,7 @@ func TestMain(m *testing.M) { | |
DB: testDB, | ||
Client: testAPIClient, | ||
Account: testAccount, | ||
MailService: testMailService, | ||
FullTransparentMode: false, | ||
}).Start() | ||
// wait for the API to start | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package api | ||
|
||
const ( | ||
// VerificationCodeLength is the length of the verification code in bytes | ||
VerificationCodeLength = 3 | ||
// VerificationCodeEmailSubject is the subject of the verification code email | ||
VerificationCodeEmailSubject = "Vocdoni verification code" | ||
// VerificationCodeTextBody is the body of the verification code email | ||
VerificationCodeTextBody = "Your Vocdoni verification code is: " | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,9 +13,12 @@ | |
- [π Sign message](#-sign-message) | ||
- [π₯ Users](#-users) | ||
- [π Register](#-register) | ||
- [β Verify user](#-verify-user) | ||
- [π§βπ» Get current user info](#-get-current-user-info) | ||
- [π Update current user info](#-update-current-user-info) | ||
- [π Update current user password](#-update-current-user-password) | ||
- [βοΈβπ₯ Request a password recovery](#-request-a-password-recovery) | ||
- [π Reset user password](#-reset-user-password) | ||
- [π€ Organizations](#-organizations) | ||
- [π Create organization](#-create-organization) | ||
- [βοΈ Update organization](#-update-organization) | ||
|
@@ -64,14 +67,6 @@ | |
* **Headers** | ||
* `Authentication: Bearer <user_token>` | ||
|
||
* **Response** | ||
```json | ||
{ | ||
"token": "<jwt_token>", | ||
"expirity": "2024-08-21T11:26:54.368718+02:00" | ||
} | ||
``` | ||
|
||
* **Errors** | ||
|
||
| HTTP Status | Error code | Message | | ||
|
@@ -192,6 +187,29 @@ This endpoint only returns the addresses of the organizations where the current | |
"password": "secretpass1234" | ||
} | ||
``` | ||
|
||
* **Errors** | ||
|
||
| HTTP Status | Error code | Message | | ||
|:---:|:---:|:---| | ||
| `401` | `40001` | `user not authorized` | | ||
| `400` | `40002` | `email malformed` | | ||
| `400` | `40003` | `password too short` | | ||
| `400` | `40004` | `malformed JSON body` | | ||
| `500` | `50002` | `internal server error` | | ||
|
||
### β Verify user | ||
|
||
* **Path** `/auth/verify` | ||
* **Method** `POST` | ||
* **Request Body** | ||
```json | ||
{ | ||
"email": "[email protected]", | ||
"code": "******", | ||
} | ||
``` | ||
|
||
* **Response** | ||
```json | ||
{ | ||
|
@@ -205,8 +223,6 @@ This endpoint only returns the addresses of the organizations where the current | |
| HTTP Status | Error code | Message | | ||
|:---:|:---:|:---| | ||
| `401` | `40001` | `user not authorized` | | ||
| `400` | `40002` | `email malformed` | | ||
| `400` | `40003` | `password too short` | | ||
| `400` | `40004` | `malformed JSON body` | | ||
| `500` | `50002` | `internal server error` | | ||
|
||
|
@@ -288,7 +304,7 @@ This method invalidates any previous JWT token for the user, so it returns a new | |
|
||
### π Update current user password | ||
|
||
* **Path** `/users/me/password` | ||
* **Path** `/users/password` | ||
* **Method** `PUT` | ||
* **Request body** | ||
```json | ||
|
@@ -307,6 +323,47 @@ This method invalidates any previous JWT token for the user, so it returns a new | |
| `400` | `40004` | `malformed JSON body` | | ||
| `500` | `50002` | `internal server error` | | ||
|
||
### βοΈβπ₯ Request a password recovery | ||
|
||
* **Path** `/users/password/recovery` | ||
* **Method** `POST` | ||
* **Request body** | ||
```json | ||
{ | ||
"email": "[email protected]", | ||
} | ||
``` | ||
|
||
* **Errors** | ||
|
||
| HTTP Status | Error code | Message | | ||
|:---:|:---:|:---| | ||
| `401` | `40001` | `user not authorized` | | ||
| `400` | `40004` | `malformed JSON body` | | ||
| `500` | `50002` | `internal server error` | | ||
|
||
### π Reset user password | ||
|
||
* **Path** `/users/password/reset` | ||
* **Method** `POST` | ||
* **Request body** | ||
```json | ||
{ | ||
"email": "[email protected]", | ||
"code": "******", | ||
"newPassword": "newpassword123" | ||
} | ||
``` | ||
|
||
* **Errors** | ||
|
||
| HTTP Status | Error code | Message | | ||
|:---:|:---:|:---| | ||
| `401` | `40001` | `user not authorized` | | ||
| `400` | `40003` | `password too short` | | ||
| `400` | `40004` | `malformed JSON body` | | ||
| `500` | `50002` | `internal server error` | | ||
|
||
## π€ Organizations | ||
|
||
### π Create organization | ||
|
@@ -333,6 +390,8 @@ This method invalidates any previous JWT token for the user, so it returns a new | |
"language": "EN" | ||
} | ||
``` | ||
By default, the organization is created with `activated: true`. | ||
|
||
If the user want to create a sub org, the address of the root organization must be provided inside an organization object in `parent` param. The creator must be admin of the parent organization to be able to create suborganizations. Example: | ||
```json | ||
{ | ||
|
Oops, something went wrong.