def test_pco_initialization(self): """Test initializing the PCO object with various combinations of arguments.""" # region Minimal Args: PAT Auth pco = pypco.PCO( 'app_id', 'app_secret', ) self.assertIsInstance(pco._auth_config, pypco.auth_config.PCOAuthConfig) self.assertIsInstance(pco._auth_header, str) self.assertEqual(pco.api_base, 'https://api.planningcenteronline.com') self.assertEqual(pco.timeout, 60) self.assertEqual(pco.upload_url, 'https://upload.planningcenteronline.com/v2/files') self.assertEqual(pco.upload_timeout, 300) self.assertEqual(pco.timeout_retries, 3) # endregion # region Minimal Args: OAUTH pco = pypco.PCO(token='abc') self.assertIsInstance(pco._auth_config, pypco.auth_config.PCOAuthConfig) self.assertIsInstance(pco._auth_header, str) self.assertEqual(pco.api_base, 'https://api.planningcenteronline.com') self.assertEqual(pco.timeout, 60) self.assertEqual(pco.upload_url, 'https://upload.planningcenteronline.com/v2/files') self.assertEqual(pco.upload_timeout, 300) self.assertEqual(pco.timeout_retries, 3) # endregion # region: Change all defaults pco = pypco.PCO( 'app_id', 'app_secret', api_base='https://bogus.base', timeout=120, upload_url='https://upload.files', upload_timeout=50, timeout_retries=500, ) self.assertIsInstance(pco._auth_config, pypco.auth_config.PCOAuthConfig) self.assertIsInstance(pco._auth_header, str) self.assertEqual(pco.api_base, 'https://bogus.base') self.assertEqual(pco.timeout, 120) self.assertEqual(pco.upload_url, 'https://upload.files') self.assertEqual(pco.upload_timeout, 50) self.assertEqual(pco.timeout_retries, 500)
def test_do_ratelimit_managed_request(self, mock_sleep, mock_request): """Test automatic rate limit handling.""" global RL_REQUEST_COUNT, RL_LIMITED_REQUESTS # Setup PCO object pco = pypco.PCO('app_id', 'secret') # Test with no rate limiting RL_REQUEST_COUNT = 0 RL_LIMITED_REQUESTS = 0 pco._do_ratelimit_managed_request('GET', '/test') mock_request.assert_called_once() mock_sleep.assert_not_called() # Test with rate limiting RL_REQUEST_COUNT = 1 RL_LIMITED_REQUESTS = 0 pco._do_ratelimit_managed_request('GET', '/test') mock_sleep.assert_called_once_with(5) # Test with rate limiting (three limited responses) RL_REQUEST_COUNT = 3 RL_LIMITED_REQUESTS = 0 result = pco._do_ratelimit_managed_request('GET', '/test') mock_sleep.assert_called_with(15) self.assertIsNotNone(result, "Didn't get response returned!")
def publish_pco_page(): pco = pypco.PCO(os.environ.get('PCO_CLIENT_ID'), os.environ.get('PCO_CLIENT_SECRET')) publish_url = pco.get(f'/publishing/v2/abstract_pages/' f'page-{os.environ.get("PCO_PUBLISHING_SLUG")}' f'') pco.post(publish_url['data']['attributes']['page_actions'][0]['url'], {}) subdomain = pco.get('/publishing/v2')['data']['attributes']['subdomain'] print( f"Published Youtube Channel content to https://{subdomain}.churchcenter.com/pages/{os.environ.get('PCO_PUBLISHING_SLUG')}" )
def post_youtube_content(): html_txt = get_youtube_json_payload_from_rss( os.environ.get('YOUTUBE_CHANNEL')) pco = pypco.PCO(os.environ.get('PCO_CLIENT_ID'), os.environ.get('PCO_CLIENT_SECRET')) slug = os.environ.get("PCO_PUBLISHING_SLUG") payload = pco.template( 'Page', { 'title': os.environ.get('PCO_PUBLISHING_TITLE'), "content": html_txt, "slug": os.environ.get('PCO_PUBLISHING_SLUG'), }) pco.post('/publishing/v2/pages', payload) return
def __init__(self, *args, **kwargs): """Initialize the test case.""" vcr_unittest.VCRTestCase.__init__(self, *args, **kwargs) try: self.creds = get_creds_from_environment() except CredsNotFoundError: self.creds = {} self.creds['application_id'] = 'pico' self.creds['secret'] = 'robot' self.pco = pypco.PCO(self.creds['application_id'], self.creds['secret']) #pylint: disable=W0201 build_logging_environment()
def __init__(self, *args, **kwargs): vcr_unittest.VCRTestCase.__init__(self, *args, **kwargs) try: self.creds = get_creds_from_environment() except CredsNotFoundError: self.creds = {} self.creds['application_id'] = 'pico' self.creds['secret'] = 'robot' self.pco = pypco.PCO( self.creds['application_id'], self.creds['secret'] ) build_logging_environment()
def _test_do_url_managed_upload_request(self, mock_request): """Test upload request with URL cleanup (should ignore).""" # Setup PCO object pco = pypco.PCO('app_id', 'secret') pco._do_url_managed_request( 'POST', 'https://upload.planningcenteronline.com/v2/files', upload='test', ) mock_request.assert_called_with( 'POST', 'https://upload.planningcenteronline.com/v2/files', headers={ 'User-Agent': 'pypco', 'Authorization': 'Basic YXBwX2lkOnNlY3JldA==' }, upload='test', json=None, params={}, timeout=60)
import pypco import os import datetime from plugins.pco import msg_attachment pco = pypco.PCO(os.environ["WILL_PCO_APPLICATION_KEY"], os.environ["WILL_PCO_API_SECRET"]) attachment_list = [] def get(name): try: fl_name = {'first_name': name.split()[0], 'last_name': name.split()[1]} except IndexError: fl_name = {'first_name': name.split()[0]} finally: for x in pco.people.people.list(where=fl_name): build(x) fl_name = fl_name = {'nickname': name} for x in pco.people.people.list(where=fl_name): build(x) return attachment_list def build(x): pcoaddress = "https://people.planningcenteronline.com/people/" + x.id if x.birthdate is None: return
import pypco from datetime import datetime, timedelta, date import date_comp as dc import credentials as cred import mailer today = datetime.today().strftime('%m-%d-%Y') pco = pypco.PCO(cred.pco_app_id, cred.pco_secret) params = {'where[child]': 'true', 'where[active]': 'true'} this_week_bdays = {} def main(): for person in pco.iterate('/people/v2/people', **params): child_name = person['data']['attributes']['name'] child_birthdate = person['data']['attributes']['birthdate'] #add child and birthdate to list if the birthdate is filled out, otherwise pass go and collect $0 if child_birthdate is None: pass else: child_birthdate = datetime.date( datetime.strptime(child_birthdate, '%Y-%m-%d')) if date.today() <= child_birthdate.replace(year=datetime.today( ).year) <= date.today() + timedelta(days=7): this_week_bdays.update({child_name: child_birthdate}) else: pass for child_name, child_birthdate in this_week_bdays.items():
import pypco import dateutil.parser from dateutil import tz import datetime from datetime import timezone import threading import schedule import time from os import system import os import logging import auth import keyboard pco = pypco.PCO(auth.id, auth.secret) #authenticate using auth.py org=pco.get('/services/v2')#get info on the organization churchname=org['data']['attributes']['name']#define churchname user=pco.get('/people/v2/me') user_id=user['data']['id'] def utc_to_local(utc_dt): #define the conversion from UTC to local time return utc_dt.replace(tzinfo=timezone.utc).astimezone(tz=None) def printit(): #define function to run every second islive=pco.get(f'/services/v2/people/{user_id}/recent_plans/{plan_id}/live/current_item_time') #get current item time file item_id=(islive['data']['relationships']['item']['data']['id']) #get the id of the current item for id in pco.iterate(f'/services/v2/people/{user_id}/recent_plans/{plan_id}/items'): #run through the list of items in a plan if (id['data']['id'])== item_id: #check if the id of an item matches the id of the current live item livestart=dateutil.parser.isoparse((islive['data']['attributes']['live_start_at']))#get the start time of the current item starttime=utc_to_local(livestart)#convert livestart to the local time zone length=datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=(id['data']['attributes']['length'])/60, hours=0, weeks=0)#convert the time to the same format as the start time endtime=(starttime+length)#calculate a predicted end time
def test_do_url_managed_request(self, mock_request): """Test requests with URL cleanup.""" base = 'https://api.planningcenteronline.com' # Setup PCO object pco = pypco.PCO('app_id', 'secret') pco._do_url_managed_request('GET', '/test') mock_request.assert_called_with('GET', f'{base}/test', headers={ 'User-Agent': 'pypco', 'Authorization': 'Basic YXBwX2lkOnNlY3JldA==' }, json=None, params={}, timeout=60) pco._do_url_managed_request( 'GET', 'https://api.planningcenteronline.com/test') mock_request.assert_called_with('GET', f'{base}/test', headers={ 'User-Agent': 'pypco', 'Authorization': 'Basic YXBwX2lkOnNlY3JldA==' }, json=None, params={}, timeout=60) pco._do_url_managed_request( 'GET', 'https://api.planningcenteronline.com//test') mock_request.assert_called_with('GET', f'{base}/test', headers={ 'User-Agent': 'pypco', 'Authorization': 'Basic YXBwX2lkOnNlY3JldA==' }, json=None, params={}, timeout=60) pco._do_url_managed_request( 'GET', 'https://api.planningcenteronline.com//test') mock_request.assert_called_with('GET', f'{base}/test', headers={ 'User-Agent': 'pypco', 'Authorization': 'Basic YXBwX2lkOnNlY3JldA==' }, json=None, params={}, timeout=60) pco._do_url_managed_request('GET', \ 'https://api.planningcenteronline.com//test///test1/test2/////test3/test4') mock_request.assert_called_with('GET', f'{base}/test/test1/test2/test3/test4', headers={ 'User-Agent': 'pypco', 'Authorization': 'Basic YXBwX2lkOnNlY3JldA==' }, json=None, params={}, timeout=60)
def get_pco() -> pypco.PCO: """Returns reuseable Planning Centre Online instance""" app_id = os.environ["PC_APPLICATION_ID"] app_secret = os.environ["PC_SECRET"] return pypco.PCO(app_id, app_secret)
def test_do_timeout_managed_request(self, mock_request): """Test requests that automatically will retry on timeout.""" global REQUEST_COUNT, TIMEOUTS # Setup PCO object and request mock pco = pypco.PCO(application_id='app_id', secret='secret') REQUEST_COUNT = 0 TIMEOUTS = 0 pco._do_timeout_managed_request( 'GET', '/test', ) self.assertEqual(REQUEST_COUNT, 1, "Successful request not executed exactly once.") REQUEST_COUNT = 0 TIMEOUTS = 1 pco._do_timeout_managed_request( 'GET', '/test', ) self.assertEqual(REQUEST_COUNT, 2, "Successful request not executed exactly once.") REQUEST_COUNT = 0 TIMEOUTS = 1 pco._do_timeout_managed_request( 'GET', '/test', ) self.assertEqual(REQUEST_COUNT, 2, "Successful request not executed exactly once.") REQUEST_COUNT = 0 TIMEOUTS = 2 pco._do_timeout_managed_request( 'GET', '/test', ) self.assertEqual(REQUEST_COUNT, 3, "Successful request not executed exactly once.") REQUEST_COUNT = 0 TIMEOUTS = 3 with self.assertRaises(PCORequestTimeoutException): pco._do_timeout_managed_request( 'GET', '/test', ) mock_request.assert_called_with('GET', '/test', headers={ 'User-Agent': 'pypco', 'Authorization': 'Basic YXBwX2lkOnNlY3JldA==' }, json=None, params={}, timeout=60) # Let's try with only two retries permitted pco = pypco.PCO(application_id='app_id', secret='secret', timeout_retries=2) REQUEST_COUNT = 0 TIMEOUTS = 2 with self.assertRaises(PCORequestTimeoutException): pco._do_timeout_managed_request( 'GET', '/test', )
def test_do_request(self, mock_fh, mock_request): """Test dispatching single requests; HTTP verbs, file uploads, etc.""" # Setup PCO object and request mock pco = pypco.PCO(application_id='app_id', secret='secret') mock_response = Mock() mock_response.status_code = 200 mock_response.text = '{"hello": "world"}' mock_request.return_value = mock_response # GET pco._do_request( 'GET', 'https://api.planningcenteronline.com/somewhere/v2/something', include='test', per_page=100) mock_request.assert_called_with( 'GET', 'https://api.planningcenteronline.com/somewhere/v2/something', params={ 'include': 'test', 'per_page': 100 }, headers={ 'User-Agent': 'pypco', 'Authorization': 'Basic YXBwX2lkOnNlY3JldA==', }, json=None, timeout=60, ) # POST pco._do_request( 'POST', 'https://api.planningcenteronline.com/somewhere/v2/something', payload={ 'type': 'Person', 'attributes': { 'a': 1, 'b': 2 } }) mock_request.assert_called_with( 'POST', 'https://api.planningcenteronline.com/somewhere/v2/something', json={ 'type': 'Person', 'attributes': { 'a': 1, 'b': 2 } }, headers={ 'User-Agent': 'pypco', 'Authorization': 'Basic YXBwX2lkOnNlY3JldA==' }, params={}, timeout=60) # File Upload mock_fh.name = "open()" pco._do_request( 'POST', 'https://api.planningcenteronline.com/somewhere/v2/something', upload='/file/path', ) mock_fh.assert_called_once_with('/file/path', 'rb')
def process(args, config): # Get PCO API credentials. pco = pypco.PCO( config['pco_app_id'], config['pco_secret'] ) pco_username = config['pco_username'] pco_password = config['pco_password'] tag_groups = [ (tg['data']['id'], tg['data']['attributes']['name']) for tg in list(pco.iterate('/groups/v2/tag_groups?per_page=100')) ] group_types = [ (gt['data']['id'], gt['data']['attributes']['name']) for gt in list(pco.iterate('/groups/v2/group_types?per_page=100')) ] print('Group Types:') for i, gt in enumerate(group_types): print('\t', i, gt[1]) gt_input = _validate_input( input(f'Please select a group type [0-{len(group_types) - 1}]: '), group_types ) if gt_input is None: logger.error('Invalid input, must be type int and within bounds.') return -1 gt_id = group_types[gt_input][0] groups = [ [g['data']['id'], g['data']['attributes']['name']] for g in pco.iterate(f'/groups/v2/group_types/{gt_id}/groups') ] for i, g in enumerate(groups): tags = [t['data']['id'] for t in pco.iterate(f"/groups/v2/groups/{g[0]}/tags")] groups[i].append(tags) for i, g in enumerate(groups): tags = [t['data']['id'] for t in pco.iterate(f"/groups/v2/groups/{g[0]}/tags")] groups[i].append(tags) print('Tag Groups:') for i, gt in enumerate(tag_groups): print('\t', i, gt[1]) tg_input = _validate_input( input(f'Please select a tag group [0-{len(tag_groups) - 1}]: '), tag_groups ) if tg_input is None: logger.error('Invalid input, must be type int and within bounds.') return -1 tg_id = tag_groups[tg_input][0] tags = [ (t['data']['id'], t['data']['attributes']['name']) for t in list(pco.iterate(f'/groups/v2/tag_groups/{tg_id}/tags')) ] print('Tags:') for i, t in enumerate(tags): print('\t', i, t[1]) t_input = _validate_input( input(f'Please select a tag [0-{len(tags) - 1}]: '), tags ) if t_input is None: logger.error('Invalid input, must be type int and within bounds.') return -1 _automate_browser_operation(config['pco_username'], config['pco_password'], groups, tags[t_input]) logger.success('App finished processing') # Return successfully return os.EX_OK
import enlighten import os import pypco import requests import time from dateutil.relativedelta import relativedelta from datetime import date LARGE_FAMILY_SIZE = 7 MINIMUM_ADULT_AGE = 16 pco = pypco.PCO(os.environ["PCO_KEY"], os.environ["PCO_SECRET"]) # Collect the number of people in PCO response = pco.get( 'https://api.planningcenteronline.com/people/v2/people?where[status]=active&per_page=0' ) people = response['meta']['total_count'] print(f"There are {people} active profiles in PCO People\n") url = "https://api.planningcenteronline.com/people/v2/households?include=people" response = pco.get(url) household_total = response['meta']['total_count'] # Setup Progress Bar manager = enlighten.get_manager() progress = manager.counter(total=household_total, desc='Retrieving from PCO', unit='households')
import pypco from dotenv import load_dotenv, find_dotenv import os import csv load_dotenv(find_dotenv(filename='secrets.env')) # Put your API secrets in the .env file pco = pypco.PCO(os.environ.get('APP_ID'), os.environ.get('APP_SECRET')) # Edit this map to change set the old Reason to the new PCO reason. # Use https://api.planningcenteronline.com/people/v2/inactive_reasons to get the reason id's. # Anything you want to map to "No Reason provided" set to None # Make sure you include your own Planning Center Inactive Reasons # https://people.planningcenteronline.com/customize#tab=personal look for "Membership Inactive Reason" reason_map = { 'Not attending': { "type": "InactiveReason", "id": "4473896" }, 'Deceased': { "type": "InactiveReason", "id": '4426198' }, 'Moved': { "type": "InactiveReason", "id": '4426196' }, 'Death': { "type": "InactiveReason", "id": '4426198'