From b8fb109b347618cc95e0f822bd85b845a1515f08 Mon Sep 17 00:00:00 2001 From: Toby Twigger Date: Wed, 29 Jul 2020 15:39:48 +0100 Subject: [PATCH] Add documentation --- .gitattributes | 1 + antora-docs/antora.yml | 6 + .../assets/images/model-relations.png | Bin 0 -> 7830 bytes antora-docs/modules/developers/nav.adoc | 4 + .../pages/additional-attributes.adoc | 36 + antora-docs/modules/developers/pages/api.adoc | 871 ++++++++++++++++++ .../modules/developers/pages/index.adoc | 78 ++ .../developers/pages/integrations.adoc | 56 ++ 8 files changed, 1052 insertions(+) create mode 100644 antora-docs/antora.yml create mode 100644 antora-docs/modules/developers/assets/images/model-relations.png create mode 100644 antora-docs/modules/developers/nav.adoc create mode 100644 antora-docs/modules/developers/pages/additional-attributes.adoc create mode 100644 antora-docs/modules/developers/pages/api.adoc create mode 100644 antora-docs/modules/developers/pages/index.adoc create mode 100644 antora-docs/modules/developers/pages/integrations.adoc diff --git a/.gitattributes b/.gitattributes index a442f15..0750ffa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,3 +12,4 @@ phpunit.xml export-ignore Doxyfile export-ignore doxygen-filters.php export-ignore composer.lock export-ignore +/antora-docs export-ignore diff --git a/antora-docs/antora.yml b/antora-docs/antora.yml new file mode 100644 index 0000000..347db64 --- /dev/null +++ b/antora-docs/antora.yml @@ -0,0 +1,6 @@ +name: control-api +title: Control (API) +version: develop +start_page: developers:index.adoc +nav: + - modules/developers/nav.adoc diff --git a/antora-docs/modules/developers/assets/images/model-relations.png b/antora-docs/modules/developers/assets/images/model-relations.png new file mode 100644 index 0000000000000000000000000000000000000000..94f76e52300205b50c6a5bfbd80cc26c63b50ed1 GIT binary patch literal 7830 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 literal 0 HcmV?d00001 diff --git a/antora-docs/modules/developers/nav.adoc b/antora-docs/modules/developers/nav.adoc new file mode 100644 index 0000000..4951cb9 --- /dev/null +++ b/antora-docs/modules/developers/nav.adoc @@ -0,0 +1,4 @@ +* xref:index.adoc[Home] +* xref:integrations.adoc[Integrations] +* xref:api.adoc[API] +* xref:additional-attributes.adoc[Additional Attributes] diff --git a/antora-docs/modules/developers/pages/additional-attributes.adoc b/antora-docs/modules/developers/pages/additional-attributes.adoc new file mode 100644 index 0000000..9f2a627 --- /dev/null +++ b/antora-docs/modules/developers/pages/additional-attributes.adoc @@ -0,0 +1,36 @@ += Additional Attributes + +To increase the flexibility of the Data Provider, we'd like to add +arbitrary properties. These can't be defined as their own column in the +database, because at some point they will be settable through the UI. +Therefore, we use the 'HasAdditionalProperties' trait. + +This trait relies on storing the additional properties in a single +column, a JSON column called 'additional_attributes'. + +.... +$table->json('additional_attributes')->nullable()->default('[]'); +.... + +In the service provider, we define the additional properties the model +can handle. This is done through the `+Model::addProperty($key)+` method +call. Two methods are then defined, `+getAdditionalAttribute($key)+` and +`+setAdditionalAttribute($key, $value)+`. These retrieve the +additional_attributes, using the defined mutator to ensure it is an +array, then return or set the correct values. + +To let us keep doing things the 'Laravel' way, we also override the get +and setAttribute functions. Before the default implementations of these +methods are called, we check to see if the user is getting or setting an +'additional property'. If they are, we pass the method call onto the +corresponding set or get additionalAttribute function, otherwise we +continue with the default method call. + +Finally, we want to automatically enter these parameters into the model +when cast to an array. To do that, the trait automatically adds +additional properties to the appends array. We then define a __call +method, which handles the method call if it's an accessor or mutator +attempt for an additional property. + +Other models must define the get and setAdditonalAttribte methods, and +return the additional attributes when casted to an array or a string. diff --git a/antora-docs/modules/developers/pages/api.adoc b/antora-docs/modules/developers/pages/api.adoc new file mode 100644 index 0000000..6250f44 --- /dev/null +++ b/antora-docs/modules/developers/pages/api.adoc @@ -0,0 +1,871 @@ += API + +By pulling the control package into your project, no matter what +integration you're using, we provide a ready-made full REST Api for +managing users. We do this by building an API on top of the repository +and model contracts, therefore the API holds independently of the +repository or model implementation logic. + +Scopes for authorization are still to be set up. For now, if +authenticated, all routes are available. + +A https://www.getpostman.com/[Postman] collection covering the below +requests can be found here: +https://www.getpostman.com/collections/e1df9930bd973737707c + +A swagger.json definition can be seen here: +https://bristol-su.github.io/control-api-docs/#/ + +== Group + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a group* + +GET + +/group + +Get all groups + +GET + +/group/\{id} + +Get a group by ID + +POST + +/group + +Create a group. Accepts a name and email + +PUT/PATCH + +/group/\{id} + +Update the group. Accepts a name and email + +DELETE + +/group/\{id} + +Delete a group + +*Tagging Groups* + +GET + +/group/\{id}/tag + +Get all tags belonging to the group + +PUT/PATCH + +/group/\{id}/tag/\{id} + +Tag the group with the tag + +DELETE + +/group/\{id}/tag/\{id} + +Delete the tag from the group + +*Managing user memberships with groups* + +GET + +/group/\{id}/user + +Get all users belonging to the group + +PUT/PATCH + +/group/\{id}/user/\{id} + +Associate the user with the group + +DELETE + +/group/\{id}/user/\{id} + +Delete the user from the group + +*Manage roles associated with the group* + +GET + +/group/\{id}/role + +Get all roles belonging to the group + +== User + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a user* + +GET + +/user + +Get all users + +GET + +/user/\{id} + +Get a user by ID + +POST + +/user + +Create a user. Accepts a first name, last name, dob, email and preferred +name + +PUT/PATCH + +/user/\{id} + +Update the user. Accepts a first name, last name, dob, email and +preferred name + +DELETE + +/user/\{id} + +Delete a user + +*Tagging Users* + +GET + +/user/\{id}/tag + +Get all tags belonging to the user + +PUT/PATCH + +/user/\{id}/tag/\{id} + +Tag the user with the tag + +DELETE + +/user/\{id}/tag/\{id} + +Delete the tag from the user + +*Managing groups memberships of users* + +GET + +/user/\{id}/group + +Get all groups the user is a member of + +PUT/PATCH + +/user/\{id}/group/\{id} + +Associate the user with a group + +DELETE + +/user/\{id}/group/\{id} + +Delete the user from a group + +*Manage roles associated with the user* + +GET + +/user/\{id}/role + +Get all roles belonging to the user + +PUT/PATCH + +/user/\{id}/role/\{id} + +Associate the role with the user + +DELETE + +/user/\{id}/role/\{id} + +Remove the role from the user + +== Role + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a role* + +GET + +/role + +Get all roles + +GET + +/role/\{id} + +Get a role by ID + +POST + +/role + +Create a role. Accepts a position_id, group_id, position name and email + +PUT/PATCH + +/role/\{id} + +Update the role. Accepts a position_id, group_id, position name and +email + +DELETE + +/role/\{id} + +Delete a role + +*Tagging Roles + +* + +GET + +/role/\{id}/tag + +Get all tags belonging to the role + +PUT/PATCH + +/role/\{id}/tag/\{id} + +Tag the role with the tag + +DELETE + +/role/\{id}/tag/\{id} + +Delete the tag from the role + +*Managing users who own a role + +* + +GET + +/role/\{id}/user + +Get all users the role belongs to + +PUT/PATCH + +/role/\{id}/user/\{id} + +Associate the role with a user + +DELETE + +/role/\{id}/user/\{id} + +Remove a role from the user + +*Group belonging to the role + +* + +GET + +/role/\{id}/group + +Get the group the role belongs to + +*Position belonging to the role + +* + +GET + +/role/\{id}/position + +Get all position the role belongs to + +== Position + +The position API is still in development + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a position + +* + +GET + +/position + +Get all positions + +GET + +/position/\{id} + +Get a position by ID + +POST + +/position + +Create a position. Accepts a name and description + +PUT/PATCH + +/position/\{id} + +Update the position. Accepts a name and description + +DELETE + +/position/\{id} + +Delete a position + +*Tagging Positions + +* + +GET + +/position/\{id}/tag + +Get all tags belonging to the position + +PUT/PATCH + +/position/\{id}/tag/\{id} + +Tag the position with the tag + +DELETE + +/position/\{id}/tag/\{id} + +Delete the tag from the position + +*Managing roles who use the position + +* + +GET + +/position/\{id}/role + +Get all roles that use the position + +== Group Tags + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a group tag + +* + +GET + +/group-tag + +Get all group tags + +GET + +/group-tag/\{id} + +Get a group tag by ID + +POST + +/group-tag + +Create a group tag. Accepts a name, description, reference and tag +category id + +PUT/PATCH + +/group-tag/\{id} + +Update the group tag. Accepts a name, description, reference and tag +category id + +DELETE + +/group-tag/\{id} + +Delete a group tag + +*Tagging Groups + +* + +GET + +/group-tag/\{id}/group + +Get all groups belonging to the group tag + +PUT/PATCH + +/group-tag/\{id}/group/\{id} + +Tag the group with the group tag + +DELETE + +/group-tag/\{id}/group/\{id} + +Delete the group from the group tag + +*Group Tag Category* + +GET + +/group-tag/\{id}/group-tag-category + +Get the group tag category for the tag + +== Group Tag Categories + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a group tag category + +* + +GET + +/group-tag-category + +Get all group tag categories + +GET + +/group-tag-category/\{id} + +Get a group tag category by ID + +POST + +/group-tag-category + +Create a group tag category. Accepts a name, description and reference + +PUT/PATCH + +/group-tag-category/\{id} + +Update the group tag category. Accepts a name, description and reference + +DELETE + +/group-tag-category/\{id} + +Delete a group tag cagegory + +*Manage Group Tags + +* + +GET + +/group-tag-category/\{id}/group-tag + +Get all group tags belonging to the group tag category + +== User Tags + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a user tag + +* + +GET + +/user-tag + +Get all user tags + +GET + +/user-tag/\{id} + +Get a user tag by ID + +POST + +/user-tag + +Create a user tag. Accepts a name, description, reference and tag +category id + +PUT/PATCH + +/user-tag/\{id} + +Update the user tag. Accepts a name, description, reference and tag +category id + +DELETE + +/user-tag/\{id} + +Delete a user tag + +*Tagging users + +* + +GET + +/user-tag/\{id}/user + +Get all users belonging to the user tag + +PUT/PATCH + +/user-tag/\{id}/user/\{id} + +Tag the user with the user tag + +DELETE + +/user-tag/\{id}/user/\{id} + +Delete the user from the user tag + +*User Tag Category* + +GET + +/user-tag/\{id}/user-tag-category + +Get the user tag category for the tag + +== User Tag Categories + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a user tag category + +* + +GET + +/user-tag-category + +Get all user tag categories + +GET + +/user-tag-category/\{id} + +Get a user tag category by ID + +POST + +/user-tag-category + +Create a user tag category. Accepts a name, description and reference + +PUT/PATCH + +/user-tag-category/\{id} + +Update the user tag category. Accepts a name, description and reference + +DELETE + +/user-tag-category/\{id} + +Delete a user tag cagegory + +*Manage user Tags + +* + +GET + +/user-tag-category/\{id}/user-tag + +Get all user tags belonging to the user tag category + +== Position Tags + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a position tag + +* + +GET + +/position-tag + +Get all position tags + +GET + +/position-tag/\{id} + +Get a position tag by ID + +POST + +/position-tag + +Create a position tag. Accepts a name, description, reference and tag +category id + +PUT/PATCH + +/position-tag/\{id} + +Update the position tag. Accepts a name, description, reference and tag +category id + +DELETE + +/position-tag/\{id} + +Delete a position tag + +*Tagging positions + +* + +GET + +/position-tag/\{id}/position + +Get all positions belonging to the position tag + +PUT/PATCH + +/position-tag/\{id}/position/\{id} + +Tag the position with the position tag + +DELETE + +/position-tag/\{id}/position/\{id} + +Delete the position from the position tag + +*Position Tag Category* + +GET + +/position-tag/\{id}/position-tag-category + +Get the position tag category for the tag + +== Position Tag Categories + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a position tag category + +* + +GET + +/position-tag-category + +Get all position tag categories + +GET + +/position-tag-category/\{id} + +Get a position tag category by ID + +POST + +/position-tag-category + +Create a position tag category. Accepts a name, description and +reference + +PUT/PATCH + +/position-tag-category/\{id} + +Update the position tag category. Accepts a name, description and +reference + +DELETE + +/position-tag-category/\{id} + +Delete a position tag cagegory + +*Manage position Tags + +* + +GET + +/position-tag-category/\{id}/position-tag + +Get all position tags belonging to the position tag category + +== Role Tags + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a role tag + +* + +GET + +/role-tag + +Get all role tags + +GET + +/role-tag/\{id} + +Get a role tag by ID + +POST + +/role-tag + +Create a role tag. Accepts a name, description, reference and tag +category id + +PUT/PATCH + +/role-tag/\{id} + +Update the role tag. Accepts a name, description, reference and tag +category id + +DELETE + +/role-tag/\{id} + +Delete a role tag + +*Tagging roles + +* + +GET + +/role-tag/\{id}/role + +Get all roles belonging to the role tag + +PUT/PATCH + +/role-tag/\{id}/role/\{id} + +Tag the role with the role tag + +DELETE + +/role-tag/\{id}/role/\{id} + +Delete the role from the role tag + +*Role Tag Category* + +GET + +/role-tag/\{id}/role-tag-category + +Get the role tag category for the tag + +== Role Tag Categories + +*Method* + +*Endpoint* + +*Description* + +*Standard REST endpoints for a role tag category + +* + +GET + +/role-tag-category + +Get all role tag categories + +GET + +/role-tag-category/\{id} + +Get a role tag category by ID + +POST + +/role-tag-category + +Create a role tag category. Accepts a name, description and reference + +PUT/PATCH + +/role-tag-category/\{id} + +Update the role tag category. Accepts a name, description and reference + +DELETE + +/role-tag-category/\{id} + +Delete a role tag cagegory + +*Manage role Tags + +* + +GET + +/role-tag-category/\{id}/role-tag + +Get all role tags belonging to the role tag category diff --git a/antora-docs/modules/developers/pages/index.adoc b/antora-docs/modules/developers/pages/index.adoc new file mode 100644 index 0000000..c1612cb --- /dev/null +++ b/antora-docs/modules/developers/pages/index.adoc @@ -0,0 +1,78 @@ += Introduction + +Control is the user management system for the Bristol SU Portal. The +complexity of the user management structure was borne from the +student-led society hierarchical structure. A student-led society is +called a group. A group has many members, which are users. Additionally, +a group has many roles, which may be occupied by a number of users. In +reality, this allows us to assign users to committee roles (for example, +a President, Secretary, Treasurer etc), as well as allow users to be +members of groups. + +When worded in this way, the group system seems very restrictive for +non-unions or non-group services. However, there is no requirement that +says a group must be a student-led society. For example, a group may be +a department in an office. Each individual could have a different role, +or some individuals may be members and a hierarchical structure can be +built above them (e.g. line manager, budget holder etc). Similarly, a +group could represent a house for a letting agent. Tenants would be +'members' of the group, and the agent responsible for the house could +hold a role in the group. + +In this way, a huge amount of additional flexibility and customization +can be achieved over a simple user model. Activities can be made open to +only those in a role, or a role with a specific position. Services can +be set up to require different steps to be completed by different +people, which would not be as achievable or scalable than a simple user +model. + +The following diagram shows the relationships between Users, Groups and +Roles. + +image::model-relations.png[] + +The relationship between Users, Groups and +Roles. + +Each of these models can also be tagged. A tag is a simple model with a +name and a reference. For example, we may want to tag a group with the +'High Risk' tag, to represent a high financial risk. In this way, we can +make an annual budget mandatory for any high risk groups. However, there +could be a situation where we have another 'High Risk' tag, meaning a +group regularly does high risk activities. Obviously we need to separate +out these tags so no confusion occurs. To do this, we use tag +categories. These are parent tags, which hold many child tags which are +then applied to a model. For example, we could create a 'Financial Risk' +category and a 'Physical risk' category, and assign them to the correct +tags to reduce confusion. + +We also need a human-friendly way of referencing the tags. Instead of +saying 'High Financial Risk', which will only work for some tags, or +'High Risk with a category of Financial Risk', we say +'financial_risk.high' (Financial Risk 'dot' High). This structure comes +from a 'reference' of both the category and tag. The reference must be +unique, and is thought of as a unique ID. Since both the parent and +child have a different reference, we join the references with a dot to +create the unique tag reference. In this way, we can reference both high +risk tags as + +'financial_risk.high' + +'physical_risk.high' + +Another important part of the user management structure is the idea of a +'Data Provider'. Many unions and other companies have a database of user +information, or for data protection reasons outsource the storing of +data to a third party. The portal therefore provides a structure to +allow integration with these providers, without enforcing their use. The +four base models (User, Group, Role and Position) all hold very little +information. In fact, they only hold relations to one another and a data +provider ID. This means that, in the case of a data breach, there is no +identifiable data held in the platform. In order to get the identifiable +information for use, we call the data() function on any model. This will +return a second model, whose purpose is to store information such as +names, emails, dates of birth etc. + +Using this method provides no disadvantage for data stored in the +database, but allows for external data providers to be slotted into +place and used to retrieve the data. diff --git a/antora-docs/modules/developers/pages/integrations.adoc b/antora-docs/modules/developers/pages/integrations.adoc new file mode 100644 index 0000000..ab44b82 --- /dev/null +++ b/antora-docs/modules/developers/pages/integrations.adoc @@ -0,0 +1,56 @@ += Integrations + +To allow for custom integrations to be built, Control is built on a set +of interfaces. + +== Repositories + +There is a repository per model, which allows us to create, retrieve, +update and delete any models. These should always be used for any +interaction with single Control models or retrieving relationship models +when the relationship is a many-to-one, since new implementations can be +built and bound to the container, then resolved without changing any +code. This means that the portal can handle any integrations if they +implement the correct repository contract. + +== Models + +The repositories will often return model implementations, which also +extend a specific interface to allow us to control how the data is +stored and retrieved. These models implement methods around data +storage, i.e. id(), name() etc. They also implement helpful methods to +do with retrieving relationships. Of course, this doesn't sound great as +all models should retrieve relationships the same way (using the correct +repository). Therefore, for each model, we provide a 'ModelTrait' class +to implement the common functionality + +== Data Models + +You will notice that for each of the four core models (group, user, role +and position), there is a 'data' version, which holds any identifiable +information about the model. This reduces the normal models to linking +to the data model, and all identifiable data is kept in the data model. +By default, each data model registers a few optional fields which could +apply. For example, user defines name, dob and email fields. Group +defines a name and description field. + +== Additional Properties + +Of course, you may have a use case where you need another bit of data on +the data model, for example we need a student ID in the user model. This +is what additional properties are for. Each of the four data models +implement 'ImplementsAdditionalProperties', which requires a few methods +around adding possible additional properties, and getting/setting the +additional properties. By default, using the 'HasAdditionalProperties' +trait will implement these methods for an eloquent model. + +== Pivots + +There are essentially 6 different pivoted relationships. These are +controlled by their own repository, allowing us to change, for example, +the role and user implementation, but still use the database for +connecting the two. + +== Tags + +Can use the command to seed fake data