Perth-Artifactory / taiga_sync

Utilities that adapt Taiga to our organisation
0 stars 0 forks source link

Taiga sync

CRM-ish workflows tacked onto a kanban board innit

Kanban/Taiga nomenclature

Issue syncing

Takes issues from a Slack channel and adds them to a project's issues. This typically requires a corresponding Slack workflow.

Usage

issue_sync.py

Nomenclature

Statuses

ID Status Description
1 Reported Things reported from outside the slack workflow, primarily used for volunteers to jot down things
2 Triaged User stories that have had priorities set from the Reported status or have been triaged from a reported issue
3 Investigating Some amount of experienced investigation is required and a path set out for progression
4 Ready for action Has tasks that are ready for people to complete
5 Resolving Moved from Ready for action once someone takes on the tasks that are ready for completion. Things that are being handled already should be here.
6 Resolved Once the problem has been solved

Attendee tracking

Tracks attendee interactions with the AF bureaucracy

Usage

attendee.py

Nomenclature

Statuses

ID Status Description
1 Intake Where new email queries appear
2 Prospective Someone that might attend the space
3 Attendee Day Pass attendees
4 New Member People that have signed up as a member
5 Member People that have started to "settle in" as members
6 Prospective Keyholder People that should be considered for a key
7 Keyholder People going through the keyholder process

Tasks

Tasks are arranged so that once all tasks in a status are complete the attendee is considered a "good \<category>"

Task Templated in Default Status Closed by code Closed by status Removed by status Position justification
Respond to query 1.Intake Not started ❔Req email proc ✅3.Attendee 4.New Member The root status that user stories are created under when they start as an email query
Determine project viability 2.Prospective Not started ❔Req email gpt ➖ N/A 5.Member (comp) Could conceivably be moved to 3.Attendee but this way we can mark the task as failed if it's clear from an enquiry email that we're not a suitable workshop
Encourage to visit 2.Prospective Optional ❔Req email gpt ✅5.Member N/A The primary target/goal for this status
Visit 2.Prospective Not started ➖ N/A ✅3.Attendee 4.New Member Primarily used to trigger the move to the next status
Join Slack 3.Attendee External ➖ N/A N/A Slack sign up is typically promoted during the first visit. Until this happens it shouldn't be treated as a blocker for progression
Participated in an event 3.Attendee Optional ➖ N/A ➖ N/A 7.Keyholder The primary target/goal for this status
Signed up as a visitor 3.Attendee External ➖ N/A 4.New Member Not required in the earlier statuses
Valid emergency contact details 3.Attendee External ➖ N/A 4.New Member Required for all attendees
Discussed moving to membership 3.Attendee Optional ➖ N/A 4.New Member Some attendees don't want to progress to membership, included here so we can indicate/track that
Completed new visitor induction 3.Attendee External ➖ N/A 4.New Member A required step for attendees
Signed up as member 3.Attendee External ✅4.New Member 5.Member Here primarily to allow for programmatic progression
New member induction 4.New Member External ➖ N/A N/A A required step for new members
Planned first project 4.New Member Not started ✅ 6mo member ➖ N/A N/A A key to success as a member. Tracked here instead of in 3.Attendee because we don't offer the same level of support with this to non members
Attending events as a member 4.New Member Optional ➖ N/A ➖ N/A 6.Pros Keyholder Getting new members settled into events is key
Added to billing groups 4.New Member External ➖ N/A N/A A required bureaucratic step for new members
Received at least one induction 4.New Member External ➖ N/A N/A
Concession proof sighted 4.New Member External ➖ N/A N/A Typically completed as part of new member induction
Held membership for 2+ weeks 4.New Member External ✅ 2wk member ✅7.Keyholder N/A
Communicated an issue effectively 4.New Member Optional ➖ N/A ➖ N/A ➖ N/A
No indication of CoC violations 5.Member Not started ✅ has_key ✅7.Keyholder 8.Settled
Competent to let people in 5.Member Not started ✅ has_key ✅7.Keyholder 8.Settled
Can work unsupervised 5.Member Not started ✅ has_key ✅7.Keyholder 8.Settled
Undertakes tasks safely 5.Member Not started ✅ has_key ✅7.Keyholder 8.Settled
Cleans work area 5.Member Not started ✅ has_key ✅7.Keyholder 8.Settled
Communicates issues to mngt 5.Member Not started ✅ has_key ✅7.Keyholder 8.Settled
Pays invoices without issue 5.Member Not started ✅ 18mo member ✅7.Keyholder 8.Settled
Suggested key application/nom 5.Member Blocked ✅ has_key ✅7.Keyholder 8.Settled Tracking when a responsible person is willing to push for a key
Keyholder motion put to vote 6.Pros Keyholder Not started ✅ has_key ✅7.Keyholder N/A A required bureaucratic step for keyholder applications
Keyholder motion successful 6.Pros Keyholder Blocked ✅ has_key ✅7.Keyholder N/A A required bureaucratic step for keyholder applications
Confirmed photo on tidyhq 6.Pros Keyholder External ➖ N/A N/A A required bureaucratic step for keyholder applications
Confirmed paying via bank 6.Pros Keyholder External ➖ N/A N/A A required bureaucratic step for keyholder applications
Send keyholder documentation 6.Pros Keyholder Blocked ✅ has_key ✅7.Keyholder N/A A required bureaucratic step for keyholder applications
Send bond invoice 6.Pros Keyholder External ✅7.Keyholder N/A A required bureaucratic step for keyholder applications
Confirm bond invoice paid 6.Pros Keyholder External ✅7.Keyholder N/A A required bureaucratic step for keyholder applications
Keyholder induction completed 6.Pros Keyholder External ➖ N/A N/A A required bureaucratic step for keyholder applications
3 month check in post key 7.Keyholder Not started ➖ N/A ➖ N/A N/A Some members will rest here
Discussed volunteering 7.Keyholder Not started ➖ N/A ➖ N/A N/A Some members will rest here

Loop order

If any of these steps indicate that they've made changes to the board the entire loop will be run again.

  1. Map email addresses to TidyHQ contacts
    • Looks for stories with the email address field set but no TidyHQ contact set. Replaces the email address field when we have a corresponding TidyHQ field.
    • Email addresses are mapped first so we don't duplicate stories that come from both email enquiries and TidyHQ sign ups.
  2. Create new stories based on TidyHQ contacts Looks for any TidyHQ membership that is not expired and creates a prospective story if there's no story on the board with that TidyHQ ID set. This step is skipped if --import is not passed at runtime.
  3. Use the column template to add tasks to newly created/progressed cards Adds template tasks for the current story status if they haven't been added before. Previous additions are tracked in template_actions.json.
  4. Tick off tasks that can be closed by code Processing functions are mapped to task strings, renaming a task will break closing by code
  5. Progress user stories based on task completion If all tasks on the current story are marked as complete progress the story to the next column. This checks against all tasks not just ones added by the current column template.
  6. Tick off tasks that can be closed by story status
  7. Progress stories based on TidyHQ sign up If a prospective/intake story has a TidyHQ ID set then that story has naturally progressed to the next stage outside of Taiga. Most of the close by code steps don't begin until status 3 so this has been added as a quality of life measure primarily for stories created by the TidyHQ sync step.
  8. Progress stories based on AF membership If an attendee story has a membership progress them to the new member column

Service load considerations

Get Taiga token

Some of this code cannot easily refresh tokens so we can generate a long lived one using the code below (ran on the Taiga host)

from datetime import timedelta
from taiga.users.models import User
from taiga.auth.tokens import AccessToken
AccessToken.lifetime = timedelta(days=365*100)
AccessToken.lifetime
user = User.objects.get(email="email@address")
token = AccessToken.for_user(user)
print(token)