API development

This should be the one-and-only topic for everything about adapting the Climate Gains backend API. Fortunately, the ITMO API on which this is based was a good fit for our purposes, so not too many adaptations will be needed.

We also have an up-to-date set of Climate Gains Backend API Docs. (Request group membership in Collaborators of Climate Gains if you cannot see this content.)

First thing to discuss here: the login process, as requested by @owen.

It’s relatively simple:

  • Login is done with the POST /api/v1/auth/login endpoint.

  • In addition, there is POST /api/v1/auth/authenticate, to send the one-time password (OTP) that has been delivered after calling the login endpoint. But we don’t want this 2FA hassle, esp. as our users often own only one device anyway. So we need to change the software to make authentication optional in the configuration. As a result, the “authenticate” and “resend-otp” API endpoints are not relevant for us.

  • In addition, there is a GET /api/v1/token endpoint. Presumably to refresh the JWT token occasionally, in order to keep logged in. JWT is in use for sure for user authentication, as told by the backend API Readme file:

    JWT takes care about authentication with token and refresh token.” (source)

For details about the API endpoint parameters and such, compare the Climate Gains Backend API Docs. (Request group membership in Collaborators of Climate Gains if you cannot see this content.)

Second thing to discuss is an overview of the existing UNDP ITMO API, plus the adaptations we have to make to it. (@owen, this provides the high-level overview that you asked for.)

Below is a path diagram of the existing API. For all the details about which endpoint does what, see the Swagger-generated Climate Gains Backend API Docs. (Request group membership in Collaborators of Climate Gains if you cannot see this content.)

In the diagrams below, everything in yellow is about changes we have to make. Everything else is the existing API. As is obvious, we don’t need many changes … it’s quite a good fit. The only bigger open question I still have to investigate is if and how we can recycle “countries” as project templates, providing what we call “Climate Actions” entries in our app.

(click on the image to see it in original size)

BackendAPIOverview.ClimateGains.vDraft1.3-exported.pdf (530.4 KB)

(PDF version of the above diagram)

After some more thought, here is an updated version of the API overview diagram, incl. our proposed changes to the ITMO Backend API.

(click on the image to see it in original size)

BackendAPIOverview.v0.3.0.4-exported.pdf (247.5 KB)
(PDF version of the above diagram)

This is enough planning for the API, I suggest. Originally I wanted to also provide a Swagger API documentation before implementation, just as the Swagger docs for the existing API. However, that is not suited for the tooling in Nest.js, which can generate OpenAPI specs (“Swagger docs”) from an API implementation, but not the other way around.

So instead, I will now simply implement the proposed API changes in the order required by @owen’s work, starting with the changes to endpoints /v1/auth, /v1/users and /v1/programmes. (So Owen, in about a week please let me know which adaptations you need after these.)

Some questions @matthias :

  1. I am logging in correctly with credentials via cURL but not able to authenticate with the /auth/authenticate endpoint. Here is the request made:
curl -X "POST" "http://api.climategains.org:9092/api/v1/auth/authenticate" \
    -H 'x-api-key: rpA94jzJjrBh9IclvNKvM34xhHwo282g7qZ6mJ0sKITOBy39' \
    -H 'Content-Type: text/plain; charset=utf-8' \
    -d $'{
 "otp": "123456"
}
  1. Accessing the /programmes endpoint provides me with action templates - not the actions themselves. We would like the app to display the results of user actions and not those templates (which are managed by an admin)? Therefore the actions index should be calling the /projects endpoint. Calling this endpoint returns a 401 Unauthorised Error.
curl "http://api.climategains.org:9092/api/v1/projects" \
     -H 'x-api-key: rpA94jzJjrBh9IclvNKvM34xhHwo282g7qZ6mJ0sKITOBy39' \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d $'{
  "email": "owen@edgeryders.eu",
  "password": "password_hidden"
}'
  1. If we are to use this endpoint, in what manner are we storing the JSON data (media, meta, steps) under each entry? I see an array for “steps”, but it does not correspond to all the data points we need in the app. This is kind of important if we want the UI to display coherent examples in the demo. We discussed storing the JSON as raw text in a value but it seems important to establish an example in the current backend?

The dummy JSON response currently used in the app below will require quite a bit of fleshing out in the backend if we want to demonstrate a complete action in the demo.

{
	"response": [{
			"id": "12982",
			"meta": {
				"title": "Bisate Reforestation Program",
				"createdAt": "2022-12-01T16:49:00.370Z",
				"author": "479c55b5-0731-4ad9-9012-a9e56f341399",
				"icon": "tree",
				"location": {
					"lat": "0.317714",
					"long": "32.5813539",
					"town": "Kampala",
					"country": "Rwanda",
					"iso": "RWA"
				},
				"funding": {
					"source": "Climate Gains",
					"currency": "EUR",
					"total": 1670,
					"carbon": 1200,
					"hours": 40
				}
			},
			"media": {
				"poster": "https://wsimages.wilderness-safaris.com/uploads/medium/file/20546/small_focal_Bisate_44.jpg",
				"video": {
					"url": "https://2050today.org/wp-content/uploads/2020/07/Video-Placeholder.mp4?_=1",
					"caption": "video caption"
				},
				"gallery": [{
						"url": "https://imagizer.imageshack.com/img924/4753/dvNGXY.jpg",
						"caption": ""
					},
					{
						"url": "https://imagizer.imageshack.com/img922/2741/vNdRs7.jpg",
						"caption": ""
					},
					{
						"url": "https://imagizer.imageshack.com/img923/5967/Lh2ymu.jpg",
						"caption": ""
					}
				]
			},
			"steps": [{
					"title": "Installation of Counters",
					"funds": "400",
					"hours": 10,
					"materials": "Wood, tiles, tools",
					"risks": "Must conform to health and safety guidelines",
					"technical_support": {
						"name": "",
						"address": "",
						"phone": "",
						"email": ""
					},
					"suppliers": [
						2872892,
						2387872,
						238738237
					]
				},
				{
					"title": "Purchase of Materials",
					"funds": "350",
					"hours": 5,
					"risks": "Supply chain issues could slow down the process",
					"materials": "Transportation",
					"technical_support": false,
					"suppliers": [
						2872892,
						2387872,
						238738237
					]
				},
				{
					"title": "Installation of Stoves",
					"funds": "1000",
					"hours": 25,
					"risks": "Supply chain issues could slow down the process",
					"materials": "Transportation",
					"technical_support": false,
					"suppliers": [
						2872892,
						2387872,
						238738237
					]
				}
			],
			"application": {
				"user_id": "479c55b5-0731-4ad9-9012-a9e56f341338",
				"status": "pending",
				"contract": "uid",
				"questions": [{
						"text": "Tell us how you plan to execute this project?",
						"duration": 200
					},
					{
						"text": "Question 2",
						"duration": 200
					}
				]
			}
		},
		{
			"id": "12983",
			"meta": {
				"title": "Kabulosake Solar Farm",
				"createdAt": "2022-12-01T16:49:00.370Z",
				"author": "479c55b5-0731-4ad9-9012-a9e56f341399",
				"currency": "euro",
				"icon": "sun",
				"location": {
					"lat": "-0.208333",
					"long": "31.497778",
					"country": "Uganda",
					"iso": "UGA"
				},
				"funding": {
					"source": "ClimateGains",
					"total": 1600,
					"currency": "EUR",
					"carbon": 700
				}
			},
			"media": {
				"poster": "url",
				"video": {
					"url": "https://",
					"caption": "djaksdjsdk ds asjl "
				},
				"gallery": [{
						"url": "",
						"caption": ""
					},
					{
						"url": "",
						"caption": ""
					},
					{
						"url": "",
						"caption": ""
					}
				]
			},
			"steps": {
				"step_1": {
					"title": "Installation of Counters",
					"funds": "400",
					"hours": 10,
					"materials": "Wood, tiles, tools",
					"risks": "Must conform to health and safety guidelines",
					"technical_support": {
						"name": "",
						"address": "",
						"phone": "",
						"email": ""
					},
					"suppliers": [
						2872892,
						2387872,
						238738237
					]
				},
				"step_2": {
					"title": "Purchase of Materials",
					"funds": "350",
					"hours": 5,
					"risks": "Supply chain issues could slow down the process",
					"materials": "Transportation",
					"technical_support": false,
					"suppliers": [
						2872892,
						2387872,
						238738237
					]
				},
				"step_3": {
					"title": "Installation of Stoves",
					"funds": "1000",
					"hours": 25,
					"risks": "Supply chain issues could slow down the process",
					"materials": "Transportation",
					"technical_support": false,
					"suppliers": [
						2872892,
						2387872,
						238738237
					]
				}
			},
			"questions": [{
				"text": "Tell us how you plan to execute this project?",
				"duration": 200
			}],
			"application": {
				"user_id": "479c55b5-0731-4ad9-9012-a9e56f341338",
				"status": "pending",
				"contract": "uid"
			}
		},
		{
			"id": "12985",
			"meta": {
				"title": "Eco Friendly Stoves",
				"createdAt": "2022-11-21T16:49:00.370Z",
				"author": "479c55b5-0731-4ad9-9012-a9e56f341399",
				"icon": "gas",
				"location": {
					"lat": "0.317714",
					"long": "32.5813539",
					"country": "Uganda",
					"iso": "UGA"
				},
				"funding": {
					"source": "ClimateGains",
					"total": 1000,
					"currency": "EUR",
					"carbon": 250
				}
			}
		},
		{
			"id": "12995",
			"meta": {
				"title": "Kenya Biogen",
				"createdAt": "2022-11-21T16:49:00.370Z",
				"author": "479c55b5-0731-4ad9-9012-a9e56f341399",
				"icon": "leaf",
				"location": {
					"lat": "0.317714",
					"long": "32.5813539",
					"country": "Kenya",
					"iso": "KEN"
				},
				"funding": {
					"source": "ClimateGains",
					"total": 1200,
					"currency": "EUR",
					"carbon": 150
				}
			}
		},
		{
			"id": "139390",
			"meta": {
				"title": "Ndunga Village Hyacinth Farm",
				"createdAt": "2022-11-11T16:49:00.370Z",
				"author": "479c55b5-0731-4ad9-9012-a9e56f341399",
				"icon": "leaf",
				"location": {
					"lat": "0.317714",
					"long": "32.5813539",
					"country": "Kenya",
					"iso": "KEN"
				},
				"funding": {
					"source": "ClimateGains",
					"total": 1000,
					"currency": "EUR",
					"carbon": 150
				}
			}
		}
	]
}

About the first question

Solved in chat already. For reference, you have to include the JWT token you got after the login step. And you can call the authenticate endpoint only in the state after a successful login and before a successful authentication, otherwise you also get {"statusCode":401,"message":"Unauthorized"} and then you’re logged out again and have to repeat the login step.

This worked for me:

curl 'http://api.climategains.org:9092/api/v1/auth/authenticate' \
  -X POST -H 'Accept: application/json, text/plain, /' \
  -H 'authorization: Bearer your-token-here' \
  -H 'x-api-key: rpA94jzJjrBh9IclvNKvM34xhHwo282g7qZ6mJ0sKITOBy39' \
  -H 'Content-Type: application/json' \
  --data-raw '{"otp":"123456"}'

About the second question

The Climate Actions Opportunity Index in the app is supposed to list action opportunities. Not one project executed by one user in one school, but a template that many users can use to each create their own project for it in their own location. So using the /programmes endpoint is correct for that case.

Some entries in the Climate Actions Opportunity Index are geared towards only one project to implement them. That is fine (and there will later be a property to limit the number of projects that can be crated per programme). We still distinguish between the templates in /programmes and the implementations in /projects. One programme is implemented in one-to-many projects.

For validator users, the wireframes show a list of projects (so, use the /projects endpoint in this case, and access the project’s programme entity for metadata if needed). A list of projects will work if that list does not become too long (so, enough validators doing the work).

About the third question

Yes, exactly. These API extensions are what I have been working on, and it’s now finished and (since 5 minutes) also deployed. The Swagger docs now also include detailed documentation about these new fields.

I attach here your dummy JSON response with annotations what is implemented how, and an example response from /programmes showing the new fields that you can use.

annotated current dummy JSON response (actions.json)
{
  "response": [{
      // DONE, with changes. Available in CountryResponseDto, property "id".
      // see: http://api.climategains.org:9092/docs/#model-CountryResponseDto
      "id": "12982", 
      "meta": {
        // DONE, with changes. Available in CountryResponseDto, property "name".
        // see: http://api.climategains.org:9092/docs/#model-CountryResponseDto
        "title": "Bisate Reforestation Program",
        // DONE, with changes. Available in CountryResponseDto, property "createdAt".
        // see: http://api.climategains.org:9092/docs/#model-CountryResponseDto
        "createdAt": "2022-12-01T16:49:00.370Z",
        // REMOVED. Seems unused in the app currently. And not available in the API currently.
        "author": "479c55b5-0731-4ad9-9012-a9e56f341399",
        // DONE, with changes. Added as a field "default sector" to the "Add new country" form, also 
        // used for pre-filling the project creation form's field "Sector". Then the app should 
        // decide itself which icon to use for which sector, as this is a view layer concern.
        "icon": "tree",
        "location": {
          "lat": "0.317714", // TODO: Must be optional, in case there is no precise location.
          "long": "32.5813539", // TODO: Must be optional, in case there is no precise location.
          // DONE, with changes. Added as optional new field "locationName" in the "Add new country" 
          // form. If not given, the whole country is the location. The content must be a search 
          // term that allows to display the outline of the designated area in the OpenStreetMap 
          // based mapping systemm of choice.
          "town": "Kampala",
          // REMOVED. Country name is redundant to the country's ISO code, so should not be stored. 
          // ISO code has a well-defined form without variants, so it is the better choice. 
          // Converting ISO code to name will be the client application's task.
          "country": "Rwanda", 
          // DONE. Renamed to countryCode.
          "iso": "RWA"
        },
        "funding": {
          // DONE, with changes. Added as a new field "finance.fundingSource" in the "Add new country" form in tab "Finance".
          "source": "Climate Gains",
          // DONE, with changes. Added as a new field "finance.fundingCurrency" in the "Add new country" form in tab "Finance".
          "currency": "EUR",
          // REMOVED. To be calculated in the app by summing up the hours of each step. This avoids 
          // inconsistencies.
          "total": 1670,
          // DONE, with changes. Added as a field "emissionsAvoided" to the "Add new country" form.
          // Moved outside the "funding" (now: "finance") section of the response document.
          "carbon": 1200, 
          // REMOVED. To be calculated in the app by summing up the hours of each step.
          // This avoids inconsistencies. When the field is necessary here, the calculation 
          // can be done server-side. But there will not be a field to enter this.
          "hours": 40,
        }
      },
      // TODO: Add as a new tab "Media" with fields in the "Add new country" form.
      // All fields must be optional to be compatible with the UNDP installation.
      "media": {
        // TODO: Also use "url" and "caption" sub-fields here. Caption might not be used, but can 
        // for example be displayed on click or in a tooltip. It's simpler if all these fields 
        // have the same composite data type.
        "poster": "https://wsimages.wilderness-safaris.com/uploads/medium/file/20546/small_focal_Bisate_44.jpg",
        "video": {
          "url": "https://2050today.org/wp-content/uploads/2020/07/Video-Placeholder.mp4?_=1",
          "caption": "video caption"
        },
        "gallery": [{
            "url": "https://imagizer.imageshack.com/img924/4753/dvNGXY.jpg",
            "caption": ""
          },
          {
            "url": "https://imagizer.imageshack.com/img922/2741/vNdRs7.jpg",
            "caption": ""
          },
          {
            "url": "https://imagizer.imageshack.com/img923/5967/Lh2ymu.jpg",
            "caption": ""
          }
        ]
      },
      // DONE with changes. Use the "steps" in a country's project settings for this. Include 
      // the application always as the first step (see below).
      "steps": [{
          // DONE. Use "Step Name".
          "title": "Installation of Counters",
          // TODO: Add as a field in the step creation form at the top (alongside title / description).
          // TODO: Must be a number field, as it has to be summed up in the app.
          // TODO: Rename to "prefunding".
          "funds": "400",
          // TODO: Add as a field in the step creation form at the top (alongside title / description).
          // TODO: Rename to "worktime".
          "hours": 10,
          // TODO: Add as a field in the step creation form at the top (alongside title / description).
          // TODO: Rename to "supplies". Because there are "suppliers". And because stuff like 
          // "transportation services" can hardly be counted under "materials".
          "materials": "Wood, tiles, tools",
          // TODO: Add as a field in the step creation form at the top (alongside title / description).
          "risks": "Must conform to health and safety guidelines",
          // TODO: Add as a field in the step creation form. Use a multi-line rich text field 
          // with "key: value" formatting, and keys formatted in bold. This allows to add more 
          // contact options later as desired (WhatsApp etc.).
          // TODO: Make this an optional field. If left empty, the app can render this as 
          // "Technical Support: not available" in the climate action details before applying.
          // TODO: Rename to "tech_support".
          "technical_support": {
            "name": "",
            "address": "",
            "phone": "",
            "email": ""
          },
          // TODO: Add as a field in the step creation form at the top (alongside title / description).
          // Use a multi-line rich text field with several address blocks, separated by empty lines, 
          // and the first line containing the supplier name, printed in bold. 
          // See for future plans: https://noteshub.net/X4bYPoYU8Tap
          "suppliers": [
            2872892,
            2387872,
            238738237
          ]
        },
        {
          "title": "Purchase of Materials",
          "funds": "350",
          "hours": 5,
          "risks": "Supply chain issues could slow down the process",
          "materials": "Transportation",
          "technical_support": false,
          "suppliers": [
            2872892,
            2387872,
            238738237
          ]
        },
        {
          "title": "Installation of Stoves",
          "funds": "1000",
          "hours": 25,
          "risks": "Supply chain issues could slow down the process",
          "materials": "Transportation",
          "technical_support": false,
          "suppliers": [
            2872892,
            2387872,
            238738237
          ]
        }
      ],
      // DONE with changes. An application should be submitted by filling in the form for the 
      // first step of the project. So, create a project for the climate action ("programme") first.
      // TODO: How to get a list of all projects of a certain programme that are in step 1 (i.e. in 
      // the application phase)?
      "application": {
        "user_id": "479c55b5-0731-4ad9-9012-a9e56f341338",
        // TODO: How to extract this status via the existing API? Any project step that is not 
        // yet reviewed should be recorded as "pending". Means the first step in a project must 
        // be of type "Submit & Review".
        "status": "pending",
        // TODO: What is this about? Would downloading a project's progress report help?
        "contract": "uid",
        // DONE with changes. A question is a piece of "Step Content" in a project's step, with 
        // "Content Type" set to "Upload multiple documents" (to be able to upload a video).
        "questions": [{
          // DONE with changes. Use field "Content title" of a "Step Content" item.
            "text": "Tell us how you plan to execute this project?",
            // REMOVED. Use an internal standard value instead. That is, let users 
            // record video nearly as long as they like, with a high max duration that is 
            // sufficient for all questions and would lead to automatic end of the recording.
            // That duration can be shown by the app.
            // TODO: If this solution is not sufficient at some point, add a field 
            // answer_max_duration to the step creation form to enter a max. video answer duration.
            "duration": 200
          },
          {
            "text": "Question 2",
            "duration": 200
          }
        ]
      }
    },
    {
      // ... more programme records ...
    }
  ]
}

example JSON response from /programmes
{
  "id": "63b8ac8e6b51172dbaaeef38",
  "name": "Ghana School Kitchen Programme",
  "status": "active",
  "createdAt": "2023-01-06T23:19:42.368Z",
  "updatedAt": "2023-01-06T23:19:42.368Z",
  "settings": {
    "project": {
      "steps": [
        {
          "id": "63b8ac8e6b51172dbaaeef39",
          "index": "1",
          "description": [
            {
              "language": "en",
              "text": "Test"
            }
          ],
          "prefunding": 779,
          "worktime": 21,
          "risks": "Ordinary hazards.",
          "supplies": "hand tools",
          "suppliers": "Mr. Kazanga's Universal Store",
          "tech_support": "phone: +23 456 7889900",
          "name": [
                {
                  "language": "en",
                  "text": "Test Step 1"
                }
          ],
          "type": "document-submission",
          "content": [ /* ... not relevant here … */ ],
      "monitoring": false
    },
    "applications": [ /* ... not relevant here … */ ],
    "functions": [ /* ... not relevant here … */ ],
    "finance": {
      "fundingSource": "European Union",
      "fundingCurrency": "EUR"
    },
    "media": {
      "poster": {
        "url": "myurl_1",
        "caption": "mycaption_1"
      },
      "video": {
        "url": "myurl_2",
        "caption": "mycaption_2"
      },
      "gallery": [
        {
          "url": "myurl_3",
          "caption": "mycaption_3"
        },
        {
          "url": "myurl_4",
          "caption": "mycaption_4"
        },
        {
          "url": "myurl_5",
          "caption": "mycaption_5"
        }
      ]
    }
  },
  "defaultSector": "Solar Energy",
  "countryCode": "de",
  "locationName": "Rheinland-Pfalz",
  "emissionsAvoided": 1200
}

Still to do for me: I’ll create some countries and steps in the api.climategains.org installation that have these new fields in them so you can use these with your app. Will tell you when done.

1 Like

Login, authentification and account creation through the Climate Gains API is now working in app.

I will get working on the listing of programmes and the user flow for submitting an application through the API and post an update to the Netlify deployment tomorrow PM.

1 Like

Good news, thanks! :slight_smile:

For integrating the programme listing, I should create a few dummy programmes for you in the api.edgeryders.eu installation. Will try to finish that this evening and tell you.

1 Like

Thanks, at the moment I don’t see quite how to use this data in the application - an example would be handy:

{
  "id": "638f6a7d5020beaf162c3b17",
  "name": "Pangea",
  "status": "active",
  "createdAt": "2022-12-06T16:14:53.283Z",
  "updatedAt": "2022-12-29T21:01:24.406Z",
  "settings": {
    "project": {
      "steps": [
        {
          "id": "63ae0024d9db34c3c146f692",
          "index": "1",
          "description": [
            {
              "language": "en",
              "text": "baseline situation assessment<br>"
            }
          ],
          "name": [
            {
              "language": "en",
              "text": "baseline"
            }
          ],
          "type": "document-submission",
          "content": [
            {
              "id": "63ae0024d9db34c3c146f693",
              "private": false,
              "required": false,
              "type": "upload-multiple-documents",
              "title": [
                {
                  "language": "en",
                  "text": "Baseline report"
                }
              ],
              "description": [
                {
                  "language": "en",
                  "text": "Baseline report<br>"
                }
              ]
            }
          ],
          "submitter": "developer"
        }
      ],
      "monitoring": false
    },
    "applications": [
      {
        "role": "developer",
        "identity": {
          "documents": [
            {
              "description": [
                {
                  "language": "en",
                  "text": "ID card<br>"
                }
              ],
              "name": [
                {
                  "language": "en",
                  "text": "ID card"
                }
              ],
              "id": "63ae0024d9db34c3c146f694"
            }
          ],
          "type": "onplatform"
        }
      },
      {
        "role": "validator",
        "identity": {
          "documents": [
            {
              "description": [
                {
                  "language": "en",
                  "text": "ID card<br>"
                }
              ],
              "name": [
                {
                  "language": "en",
                  "text": "ID card"
                }
              ],
              "id": "63ae0024d9db34c3c146f695"
            }
          ],
          "type": "onplatform"
        }
      }
    ],
    "functions": [
      "developer",
      "supplier"
    ]
  },
  "projectsCount": 0
}

I understand the distinction - but I don’t understand in this case why the data returned by /programmes should include specific information such as suppliers, location, tech support — if these are indeed templates that can be used as a basis for any project / location?

The lines between the two feel blurred in that the interface we created displays very specific project information (a map with location, steps, suppliers). Nadia’s wireframe for the activist user explicitly specifies for example:

Browse climate actions that are funded and looking for people onsite to carry them out

In this instance aren’t we talking about specific projects? That seems to be the opposite of the template model? It might be easier to clarify this in a call if you’re available because I’m not understanding this part well enough.

1 Like

A post was merged into an existing topic: Biweekly reporting

The templates cannot be used as a basis for “any project / location” – they are much more specific, while still being generic enough to have room for several projects that share some characteristics (suppliers, geographic area, tech support contact). It seems you had a mental model that was much more generic than the “programmes” envisaged here.

Let me give a practical example: Let’s say, Vanessa secured new funding for eco-friendly cookstove installations in schools in Uganda. This is a programme, meant to cover many schools nationwide in Uganda, and to run for several years. Each installation of stoves in one school is a project. Each project might be executed by a different group of activists, and will have its own approval process and payout schedules. Projects of the same programme however share some characteristics, so that we don’t have to enter this information hundreds of times. And that is what you see configured in the programme:

  1. A geographic area to which the programme is applicable. This is not a point-like address but rather a named area, such as a country or state inside a country. Projects will have an exact geolocation, but programmes do not.

    (There’s actually a mistake in my file “annotated current dummy JSON response (actions.json)” above, where an exact location is marked optional for a programme, while the current API now has only countryCode and locationName.)

  2. A set of steps to execute one after the other to finish the project.

  3. A pre-payment amount (“budget”) for each step.

  4. A list of recommendable (or even pre-approved) suppliers. These can be from the whole area in which the programme is applicable, and activists will then select one of the closest ones to their project location.

  5. Media files, funding information, information about GHG emission savings per project and other stuff. You get the idea.

The reason for the project / programme distinction is that institutional funders usually don’t work at the level of approving work worth a few kEUR individually. Too much work. When needed, it’s still possible to execute a one-off project in this system, by creating a programme that will have only a single project attached to it. According to @OmaMorkie, we will need both options.

Does this answer your question @owen? If not, happy to have a call. Even this evening.

The following API documentation incl. examples is now available and should hopefully be sufficient to bring you to the point of listing the climate action opportunities from the API, and showing details about each on click. (Once you get to the step “Sign up for action”, I should have more documentation and an example ready to help with that.)

  1. Did you find the example in my post above (click arrow there to unfold)?

    That example contains only one step, to be used in derived project for the applications. Real projects would of course have additional implementation steps.

  2. Above there is also a file with comments to help you transition from your current actions.json interface to the API as implemented. I think this will be the most helpful for you right now.

  3. Also relevant at this stage, to give you an overview, is the Noteshub note “feature usage in the Climage Gains software”, explaining for each user type how I have mapped existing ITMO platform features to the features we need.

    Especially:

  4. The Swagger UI documentation contains usage information about the fields I added.

  5. A complete example is available from api.climategains.org now via following command:

    curl -w "\n" 'http://api.climategains.org:9092/api/v1/countries/638f6a7d5020beaf162c3b17' -H 'x-api-key: rpA94jzJjrBh9IclvNKvM34xhHwo282g7qZ6mJ0sKITOBy39' | jq
    

Much clearer, thanks for explaining and the updated examples. I’ve studied the annotated response and will aim to finish integrating the /programmes via API by tonight, at the latest tomorrow.

Still having issues with GET and POST requests to /api/v1/projects returning a 401 error.

@matthias I’ll be available through the PM, but will be hard to implement the application process any further until it’s resolved.

Requests I have tried below:

curl "http://api.climategains.org:9092/api/v1/projects" \
     -H 'x-api-key: rpA94jzJjrBh9IclvNKvM34xhHwo282g7qZ6mJ0sKITOBy39'

and

curl "http://api.climategains.org:9092/api/v1/projects" \
     -H 'x-api-key: rpA94jzJjrBh9IclvNKvM34xhHwo282g7qZ6mJ0sKITOBy39' \
     -H 'Content-Type: application/json' \
     --data-raw '{
  "email": "owen@edgeryders.eu",
  "password": "*********"
}'

First answering your API related question from another topic:

I have already disabled CORS for the API when installing it. Pretty sure your error message is about you trying to access the API via HTTP protocol from a site that is using the HTTPS protocol. That is made impossible by the browser. (Your localhost version of the app will run via HTTP, so you do not see that issue there.) Now Netlify forces HTTPS, with no way to disable it. Means I have to add SSL to the API to fix this. Will do.

For this endpoint, you will need HTTP Bearer Auth authentication in addition to the x-api-key header. So, you need a successful login first. (Details.)

There were also several other hurdles, including token refresh:

In the below commands, use the HTTP Bearer Auth token for your own user, of course. Such a token expires every 15 minutes, as JWT tokens typically do, so in case you still see “401 Not Authorized” at some point, you need to call the /api/v1/token endpoint to refresh it. You’ll need the refresh token for that, which you got from the login process in addition to the access token. See docs in Swagger UI.

Here’s finally a working example process how to create a project via the API:

  1. Apply to a programme. Use the programme ID / country ID for that, which you will know from listing all available programmes before in the app. As “identityId”, just supply any bogus value, as the application will be accepted automatically (which is a custom change I made; still need to make the whole identity field optional, but for now, use a bogus value for “identityId”).

    The example below works with the country currently defined in the api.climategains.org database.

    curl 'http://api.climategains.org:9092/api/v1/me/applications' \
      -X POST -H 'Accept: application/json, text/plain, */*' 
      -H 'authorization: Bearer your-token-here' \
      -H 'x-api-key: rpA94jzJjrBh9IclvNKvM34xhHwo282g7qZ6mJ0sKITOBy39' \
      -H 'Content-Type: application/json' \
      --data-raw '{"country":"638f6a7d5020beaf162c3b17","identity":{"type":"nationalregistryid", "identityId":"123"}}'
    
  2. Application approval. The application by a developer user to a country is approved automatically by the API logic. You could see that the submitting user is now associated to the country in the API, but that is not needed. If there is no error message, the application worked and has been approved.

  3. Create a project. After successfully applying to a programme, a developer user can now create projects – as many as they like. Example command to create one (again, it works with the country currently defined in the api.climategains.org database):

    curl 'http://api.climategains.org:9092/api/v1/projects' \
      -X POST -H 'Accept: application/json, text/plain, */*' \
      -H 'authorization: Bearer your-token-ere' \
      -H 'x-api-key: rpA94jzJjrBh9IclvNKvM34xhHwo282g7qZ6mJ0sKITOBy39' \
      -H 'Content-Type: application/json' \
      --data-raw '{"country":"638f6a7d5020beaf162c3b17","monitoring": false,"name": "My Project Name","sector": "Energy Demand"}'
    

    The "sector": "Energy Demand" field does not require special values. Any non-empty string value will do. The idea is that you use the value of field defaultSector of the programme records, but this is not important at this stage.

    The project name is also free-form text and does even not have to be unique. It should identify the project. But since users should not be forced to type, probably best generate a name of the form “By <firstname> <lastname>”. Admins may later change it when needed.

2 Likes

Thanks Matt.

I tried the compiled application on a phone - the good news is everything that is critical works - including the api calls. The only major problem is the video interface for the questionnaire which is choppy to the point of being unusable.

I suspect the issue is memory allocation with web views in Ionic. I think I have a solution to it by using an Android native camera stream via this plugin that works with Ionic. I tried it this evening and it appears to function well but requires some layout changes.

I will aim to have the /projects section finished tomorrow and I think that will be everything for the demo. For now it’s been a long day and I’ll take a break.

2 Likes

Sounds good to me, and surely enough for the demo.

On my side, I still have work to do on the FileProvider implementation. So even if you would not just create the project but also enable that a user posts the application video to the first step of their new project, right now it would not be saved server-side as there’s just a dummy implementation there … . Anyway, things are coming together :slight_smile:

Good find!! Without finding something suitable, these can easily be the nightmare issues of a software project …

I just made undp_admin accounts for @nadia and @OmaMorkie in our test installation, using your <firstname>@climategains.org e-mail addresses. You should have received an invitation e-mail to that address, and from there forwarded to your regular personal e-mail account. Please accept the invitation by visiting the link and completing the signup.

Currently these accounts allow you to log in on admin.climategains.org and see and manage the data that lives there (users, projects, applications by validators). In the future, it is also the place to define new programmes.

We can use our existing Nextcloud and use the Nextcloud app to sync a local folder on the phone. Takes more time to set up, but as we probably have to talk the Ghanian partner through apk sideloading, installing nextcloud sync will be a breath.

cloud.vashgreenschools.org is working.

In other words, if you can just point to a local folder that stores all the img and video (ideally with a little structure), i think we should be able to run with it.

1 Like