5pm-hdh / churchtools-api Goto Github PK
View Code? Open in Web Editor NEWThe Churchtools-API Client is a wrapper for the churchtools-api written in PHP.
License: MIT License
The Churchtools-API Client is a wrapper for the churchtools-api written in PHP.
License: MIT License
toJson()
to the FillWithData-trait to enable json-exportLine 24 - 50
Problems:
There are Worshipsets that have the user on null
Add API-Endpoints of Public Groups
Example implementation: https://github.com/Kevinrob/guzzle-cache-middleware
Currently implemented:
//one-to-one relation (event to agenda)
$event->requestAgenda()->get();
//one-to-many relation (event to songs)
$event->requestSongs()->where('should_practice', true)->get();
The one-to-one relation does not make sense! There will be alway just one returned instance. With the implementation above there could be nonsense code like: $event->requestAgenda()->where('id', [23, 32])->orderBy('id')->get()
and you would neet to "unpack" the first array-element always using: $event->requestAgenda()->get()[0]
⚠New design rule:⚠
// the method requestCreator returns a "Person"-Model
$creator = $song->getMeta()->requestCreator()
$songs = $agenda->requestSongs()->where('should_practice', true)->get();
Upload-Method uses pure CURL for Request because Guzzle cant handle combination of header "Content-type:multipart/form-data" and option "form_params".
churchtools-api/src/Requests/FileRequestBuilder.php
Lines 58 to 92 in e144fbd
TODO: Check if there is a workaround and use Guzzle again.
The ChurchTools API has not yet implemented all functions. To use different update functions anyway, the JavaScript AJAX API is used, which is not documented. The AJAX request calls have been reverese-engineered.
Replace these calls with the REST API as soon as it provides the respective function:
See all usages for: "AjaxApi"
In #91 a method was defined to delete models. The current code breaks with the builder pattern and has to be refactored.
The PersonRequest currently contains the whole delete logic:
public static function delete(Person $person): void
{
$id = $person->getId();
if (is_null($id)) {
throw new CTModelException("ID of Person cannot be null.");
}
(new PersonRequestBuilder())->delete($id);
}
public static function delete(Person ($person): void
{
(new PersonRequestBuilder())->delete($person);
}
deleteData(string $modelId)
-method must have the visiblity protected (this is a technical api that should not be accessed from outside)delete(UpdatableModel $model)
-method must have the visibility publicThere are diffrent Image-Sizes:
Request diffrent Image Types.
Check if current given in API Token is still valid.
Add persons/birthday-Route to retrieve comming up birthdays.
before pull request / on master branch:
execute test suite:
Setter-Method for API-Token!
I am trying to load persons in a paginated style. But it looks like this does not work.
$persons = PersonRequest::where('page', 1)
->where('limit', 10)
->get();
It always loads all persons. As far as I understand the reason is that the conditions are not added as query params to the request.
Edit
Right after sending this issue, I noticed that the Pagination trait iterates over all pages and merges them.
Isn't there a way to limit the result to one page?
It would be nice if you can write down under doc/, or as docstring, what exceptions one should could expect, when
Some days ago, guzzlehttp/guzzle released v7.4.3 containing a fix for a vulnerability with severity score 8/10. For more details see here: GHSA-cwmx-hcrq-mhc3
churchtools-api requires "guzzlehttp/guzzle": "7.3.*" in composer.json, preventing the dependency to incorporate this fix.
Please consider to require "guzzlehttp/guzzle:^7" - if compatible - to get all fixes for the 7.x major version.
The authenticate-request cannot be sent to often otherwise it will fail.
The AbstractRequestBuilder contains code to validate the Http-Status-Code:
// AbstractRequestBuilder.php
public function delete(string $modelId): void
{
$url = $this->getApiEndpoint() . '/' . $modelId;
$client = CTClient::getClient();
$response = $client->delete($url);
if (!in_array($response->getStatusCode(), [200, 204])) {
throw CTRequestException::ofErrorResponse($response);
}
}
and
// AbstractRequestBuilder.php
protected function updateData(string $objectId, array $data): void
{
$url = $this->getApiEndpoint() . '/' . $objectId;
$client = CTClient::getClient();
$response = $client->patch($url, ['json' => $data]);
if ($response->getStatusCode() !== 200) {
throw CTRequestException::ofErrorResponse($response);
}
}
I think it would be better to handle the HTTP-Status Code in the CTClient itself. For this reason i created the handleResponse
function that is called by every POST, GET, PATCH and DELETE-Method:
// CTClient.php
private function handleResponse(ResponseInterface $response): ResponseInterface
{
switch ($response->getStatusCode()) {
case 401:
throw new CTAuthException("Unauthorized.", 401);
}
return $response;
}
If neccessary we could also add a second "HTTP-Method" parameter to handle distinguish HTTP-Methods differently:
private function handleResponse(ResponseInterface $reponse, string $httpMethod): ResponseInterface {}
But i think a good first shot could be to throw a CTRequestException::ofErrorResponse($response)
for every status code that is not between 200 and 299.
The Id-Property is available in all Models with nullable string property. Create AbstractModel with ID-Property and Getter. Add convenience Getter:
getIdOrFail
: return ID as String or throw CTModel-Exception (Nullsafe getter)getIdAsInteger
: return ID as Integer or null if not castablegetIdAsIntegerOrFail
: return ID as Integer or throw CTModel-ExceptiongetId
can be replaced with nullsafe getter getIdOrFail
Group
$id = $person->getId();
if (is_null($id)) {
throw new CTModelException("ID of Person cannot be null.");
} else {
$this->updateDataForModel($person, $id, $attributesToUpdate);
}
WikiCategory
if (!is_null($this->getId())) {
return WikiPageRequestBuilder::requestPageFromCategoryAndIdentifier( (string) $this->getId(), $identifier);
} else {
return null;
}
getIdAsInteger
Event
public function requestAgenda(): EventAgenda
{
return (new EventAgendaRequestBuilder((int)$this->getId()))->get();
}
Add "getFileurlAuthenticated()"-method to the file-modal to create a downloadable url without login.
Meta information ModifiedPerson is not stored in person form, but with resource identifier. Transform the given resource identifier to a person model.
Handle diffrent logged in users as session. Enable switching between these sessions, to use the diffrent ct permissons of the users
Property Weekday come sometimes in as array, and sometimes as non-array-type.
Stacktrace:
PHP Fatal error: Uncaught TypeError: Cannot assign int to property CTApi\Models\GroupInformation::$weekday of type ?array in C:\Users\ldumberger\projects\5pm-ct-export\vendor\5pm-hdh\churchtools-api\src\Models\Traits\FillWithData.php:22
Stack trace:
#0 C:\Users\ldumberger\projects\5pm-ct-export\vendor\5pm-hdh\churchtools-api\src\Models\Traits\FillWithData.php(15): CTApi\Models\GroupInformation->fillNonArrayType('weekday', 3)
#1 C:\Users\ldumberger\projects\5pm-ct-export\vendor\5pm-hdh\churchtools-api\src\Models\Traits\FillWithData.php(63): CTApi\Models\GroupInformation->fillWithData(Array)
#2 C:\Users\ldumberger\projects\5pm-ct-export\vendor\5pm-hdh\churchtools-api\src\Models\Group.php(48): CTApi\Models\GroupInformation::createModelFromData(Array)
#3 C:\Users\ldumberger\projects\5pm-ct-export\vendor\5pm-hdh\churchtools-api\src\Models\Traits\FillWithData.php(13): CTApi\Models\Group->fillArrayType('information', Array)
#4 C:\Users\ldumberger\projects\5pm-ct-export\vendor\5pm-hdh\churchtools-api\src\Models\Traits\FillWithData.php(63): CTApi\Models\Group->fillWithData(Array)
#5 C:\Users\ldumberger\projects\5pm-ct-export\vendor\5pm-hdh\churchtools-api\src\Models\Traits\FillWithData.php(44): CTApi\Models\Group::createModelFromData(Array)
#6 [internal function]: CTApi\Models\Group::CTApi\Models\Traits\{closure}(Array)
#7 C:\Users\ldumberger\projects\5pm-ct-export\vendor\5pm-hdh\churchtools-api\src\Models\Traits\FillWithData.php(43): array_map(Object(Closure), Array)
#8 C:\Users\ldumberger\projects\5pm-ct-export\vendor\5pm-hdh\churchtools-api\src\Requests\AbstractRequestBuilder.php(24): CTApi\Models\Group::createModelsFromArray(Array)
Code:
if (array() === $data) return false;
if (is_null($song)) continue;
convenience api
// request File that matches with "searchstring" and file-extension
$chordsheetFile = $arrangement->getFirstFile('chords', 'pdf');
// request Link with that matches to substring
$chordsheetFile = $arrangement->getFirstLink('multitracks.com');
Pass an "Array-Path" to the orderBy-Method:
->orderBy("meta.created_at")
This code will order the Array by the created-at attribute nested in the meta array.
I am getting this deprecation notice:
User Deprecated: The "GuzzleHttp\Client" class is considered final. It may change without further notice as of its next major version. You should not extend it from "CTApi\CTClient".
One should switch from inheritence to composition in the client.
Add "requestSongs"-Method to Request the whole songs and not just a small subset of informations;
But the selected Arrangement Id must stay!
Also add "requestArrangements" to get the selected Song Arrangements
Error in PersonUpdateRequestTest: ❌
Response for this Integration Test:
{
"message": "Forbidden to edit the field statusId",
"translatedMessage": "Keine Berechtigung um das Feld statusId zu sehen oder zu editieren",
"messageKey": "error.forbidden.edit.field",
"args": {
"field": "statusId"
},
"errors": []
}
@Naitsirch Do you run into the same issue with this Integration-Test? How we can handle this Error? Should we create a "blacklist" for update attributes? Or split the getModifiableAttributes
into getModifiableAttributesUpdate
and getModifiableAttributesCreate
?
Move the generated MD-Files from /docs/
to /docs/out/
to make clear, that these files are generated from the /docs/src/
MD-Files.
You can fill Models with Attributes, that they don't have defined as Properties.
Example-Book Model:
class BookModel
{
use FillWithData;
protected ?string $id = null;
protected ?string $title = null;
}
Then fill with data, that don't exists on BookModel e.q. Author:
$bookWithPseudoField = BookModel::createModelFromData([
"id" => 21,
"title" => "One Example Title",
"author" => "Pseudo Author" // this field is not defined in the class
]);
var_dump($bookWithPseudoField);
The FillWithData-Trait will create Author-Property on the Objekt als public member. See the result of the var_dump:
object(Tests\Unit\Requests\BookModel)#21 (3) {
["id":protected]=>
string(2) "21"
["title":protected]=>
string(17) "One Example Title"
["author"]=>
string(13) "Pseudo Author"
}
Create Model for Links that are stored in songs
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.