from zendesk import Zendesk ################################################################ ## NEW CONNECTION CLIENT ################################################################ zendesk = Zendesk( zendesk_url='https://yourcompany.zendesk.com', zendesk_username='******', zendesk_password='******', use_api_token=True, api_version=2 ) # Are you getting an error such as... # "SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed"? zendesk = Zendesk('https://yourcompany.zendesk.com', '*****@*****.**', 'passwd', client_args={ "disable_ssl_certificate_validation": True } ) ################################################################ ## TICKETS ################################################################ # List zendesk.list_tickets(view_id=1) # Must have a view defined # Create new_ticket = {
import os from config import ENV from salesforce import SalesForce from zendesk import Zendesk from migration import MigrationItem from log_helper import get_logger import helpers log = get_logger('Main') if __name__ == "__main__": migration_plan = json.load(open('migration_plan.json', 'r')) sf_config = migration_plan['salesforce'] sf = SalesForce(**sf_config) zd_config = migration_plan['zendesk'] zd = Zendesk(**zd_config) for item in migration_plan['migration_items']: if item['skip'] == False: if item['type'] == 'migration_object': migration_item = MigrationItem(sf, zd, mode=ENV, **item) if migration_item.skip == False: try: migration_item.migrate() except Exception as err: log.critical(err) raise err elif item['type'] == 'script': eval(item['script'], {"helpers": helpers, "env": ENV})
def get_zd_instance(): migration_plan = json.load(open('migration_plan.json', 'r')) zd_config = migration_plan['zendesk'] return Zendesk(**zd_config)
42730237: 'Tickets/LSM', 42730227: 'Tickets/WSM', 42771018: 'Tickets/Mobile', 42730217: 'Tickets/Insights', 44896573: 'Tickets/Browser', 42771028: 'Tickets/Platform', 42730207: 'Tickets/Other' } post_url = "https://platform-api.newrelic.com/platform/v1/metrics" guid = 'com.NewRelic.ZedScraper' #update bash_profile on server with this info zendesk = Zendesk(environ['ZENDESK_URL'], environ['ZENDESK_USERNAME'], environ['ZENDESK_APITOKEN'], use_api_token=True, api_version=2, client_args={"disable_ssl_certificate_validation": True}) platform_key = environ['NEW_RELIC_APIKEY'] view_blob = zendesk.count_many_views(ids=view_ids.keys()) counted_views = {} for view in view_blob['view_counts']: metric_name = "Component/test2/%s[Tickets]" % view_ids[view['view_id']] total_tickets = view['value'] data = { "agent": { "host": "db.zendesk.newrelic_tickets",
def main(argv=None): import sys, tempfile, argparse # Log to stdout import logging logging.basicConfig() # Declare a class for an argparse custom action. # Handles converting ascii input from argparse that may contain unicode # to a real unicode string. class UnicodeStore(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, self.dest, values.decode('utf-8')) # Options precedence: # program state defaults, which are overridden by # ~/.zdf2pdf.cfg [zdf2pdf] section options, which are overridden by # command line options, which are overridden by # -c CONFIG_FILE [zdf2pdf] section options, which are overridden by # ~/.zdf2pdf.cfg [RUN_SECTION] section options, which are overridden by # -c CONFIG_FILE [RUN_SECTION] section options # # Program state, with defaults # state = { 'verbose': False, 'json_file': None, 'categories': None, 'forums': None, 'topics': None, 'run_section': None, 'list_zdf': 'forums', 'style_file': None, 'output_file': 'PCLOADLETTER.pdf', 'title': None, 'title_class': None, 'author': None, 'date': None, 'copyright': None, 'toc': False, 'toc_class': None, 'toc_title': 'Table of Contents', 'pre_width': None, 'strip_empty': False, 'header': None, 'footer': None, 'category_sections': False, 'forum_sections': False, 'topics_heading': None, 'work_dir': tempfile.gettempdir(), 'delete': False, 'url': None, 'mail': None, 'password': '******', 'is_token': False, } argp = argparse.ArgumentParser( description='Make a PDF from Zendesk forums or entries.') argp.add_argument('-v', '--verbose', action='store_true', help='Verbose output') argp.add_argument('--json-file', action=UnicodeStore, dest='json_file', help='Zendesk entries JSON file to convert to PDF') argp.add_argument( '--categories', action=UnicodeStore, dest='categories', help='Comma separated Category IDs to download and convert to PDF') argp.add_argument( '--forums', action=UnicodeStore, dest='forums', help='Comma separated Forum IDs to download and convert to PDF') argp.add_argument( '--topics', action=UnicodeStore, dest='topics', help='Comma separated Topic (Entry) IDs to download and convert to PDF' ) argp.add_argument('-r', action=UnicodeStore, dest='run_section', help='Run pre-configured section in configuration file') argp.add_argument( '-l', action=UnicodeStore, dest='list_zdf', help="""List a forum's entries by ID and title. If no forum ID is supplied, list forums by ID and title organized by category""", nargs='?', const=state['list_zdf'], metavar='FORUM_TO_LIST') argp.add_argument('-c', action=UnicodeStore, dest='config_file', help='Configuration file (overrides ~/.zdf2pdf.cfg)') argp.add_argument('-s', action=UnicodeStore, dest='style_file', help='Style file (CSS) to <link>') argp.add_argument('-o', action=UnicodeStore, dest='output_file', help='Output filename (default: PCLOADLETTER.pdf)', default=state['output_file']) argp.add_argument('-t', action=UnicodeStore, dest='title', help='Title to be added to the beginning of the PDF') argp.add_argument( '-a', action=UnicodeStore, dest='author', help='Author line to be added to the beginning of the PDF') argp.add_argument('--date', action=UnicodeStore, dest='date', help='Date line to be added to the beginning of the PDF') argp.add_argument( '--copyright', action=UnicodeStore, dest='copyright', help='Copyright line to be added to the beginning of the PDF') argp.add_argument('--title-class', action=UnicodeStore, dest='title_class', help='CSS class to be added to title page div') argp.add_argument('--toc', action='store_true', dest='toc', help="Generate a Table of Contents (default: false)") argp.add_argument('--toc-title', action=UnicodeStore, dest='toc_title', help="ToC title (default: Table of Contents)") argp.add_argument('--toc-class', action=UnicodeStore, dest='toc_class', help='CSS class to be added to ToC div') argp.add_argument('--pre-width', action=UnicodeStore, dest='pre_width', help='Width to wrap contents of <pre></pre> tags.') argp.add_argument('--strip-empty', action='store_true', dest='strip_empty', help='Strip empty tags. (default: false)') argp.add_argument('--header', action=UnicodeStore, dest='header', help='HTML header to add to the PDF (see docs)') argp.add_argument('--footer', action=UnicodeStore, dest='footer', help='HTML footer to add to the PDF (see docs)') argp.add_argument('--category-sections', action='store_true', dest='category_sections', help='Make categories sections (default: false)') argp.add_argument('--forum-sections', action='store_true', dest='category_sections', help='Make categories sections (default: false)') argp.add_argument( '--topics-heading', action=UnicodeStore, dest='topics_heading', help='Heading to put at start of topics retrieved individually') argp.add_argument( '-w', action=UnicodeStore, dest='work_dir', help="""Working directory in which to store JSON output and images (default: temp dir)""") argp.add_argument('-d', '--delete', action='store_true', dest='delete', help="""Delete working directory at program exit (default: do not delete)""") argp.add_argument('-u', action=UnicodeStore, dest='url', help='URL of Zendesk (e.g. https://example.zendesk.com)') argp.add_argument('-m', action=UnicodeStore, dest='mail', help='E-Mail address for Zendesk login') argp.add_argument('-p', action=UnicodeStore, dest='password', help='Password for Zendesk login', nargs='?', const=state['password']) argp.add_argument( '-i', '--is-token', action='store_true', dest='is_token', help='Is token? Specify if password supplied a Zendesk token') # Set argparse defaults with program defaults. # Skip password and list_zdf as they are argparse const, not argparse default argp.set_defaults(**dict((k, v) for k, v in state.iteritems() if k != 'password' and k != 'list_zdf')) # Read ~/.zdf2pdf.cfg [zdf2pdf] section and update argparse defaults try: config_state( os.path.expanduser('~') + '/.zdf2pdf.cfg', 'zdf2pdf', state) # Skip list_zdf because it is not a config file value, not an argparse # const value, and we don't want to lose it by overwriting it with None. # Password is OK now, because we either have one from the config file or # it is still None. argp.set_defaults(**dict( (k, v) for k, v in state.iteritems() if k != 'list_zdf')) except configparser.NoSectionError: # -c CONFIG_FILE did not have a [zdf2pdf] section. Skip it. pass # Parse the command line options if argv is None: argv = sys.argv args = argp.parse_args() # Update the program state with command line options for k in state.keys(): state[k] = getattr(args, k) # -c CONFIG_FILE given on command line read args.config_file [zdf2pdf], update state if args.config_file: if state['verbose']: print('Reading config file {}'.format(args.config_file)) try: config_state(args.config_file, 'zdf2pdf', state) except configparser.NoSectionError: # -c CONFIG_FILE did not have a [zdf2pdf] section. Skip it. pass # -r RUN_SECTION given if args.run_section: if state['verbose']: print('Searching for {} in ~/.zdf2pdf'.format(args.run_section)) section_found = False try: config_state( os.path.expanduser('~') + '/.zdf2pdf.cfg', args.run_section, state) section_found = True if state['verbose']: print('Found {} in ~/.zdf2pdf'.format(args.run_section)) except configparser.NoSectionError: # ~/.zdf2pdf.cfg did not have this section. Hope it's found later. pass # -c CONFIG_FILE and -r RUN_SECTION given if args.config_file: if state['verbose']: print('Searching for {} in {}'.format(args.run_section, args.config_file)) try: config_state(args.config_file, args.run_section, state) section_found = True if state['verbose']: print('Found {} in {}'.format(args.run_section, args.config_file)) except configparser.NoSectionError: # CONFIG_FILE did not have this section. pass # If the section wasn't found, print an error and exit if not section_found: print('Error: Run section {} was not found'.format( args.run_section)) return 1 if state['categories'] or state['topics'] or state['forums'] or state[ 'list_zdf']: from zendesk import Zendesk if state['url'] and state['mail'] and state['password']: if state['verbose']: print( 'Configuring Zendesk with:\n' 'url: {}\n' 'mail: {}\n' 'password: (hidden)\n' 'is_token: {}\n'.format(state['url'], state['mail'], repr(state['is_token']))) zd = Zendesk(state['url'], zendesk_username=state['mail'], zendesk_password=state['password'], use_api_token=state['is_token']) else: msg = textwrap.dedent("""\ Error: Need Zendesk config for requested operation. Use -u, -m, -p options or a config file to provide the information. Config file (e.g. ~/.zdf2pdf.cfg) should be something like: [zdf2pdf] url = https://example.zendesk.com mail = [email protected] password = dneib393fwEF3ifbsEXAMPLEdhb93dw343 is_token = 1 """) print(msg) return 1 # All config options are in, state is set. # Handle any last minute type checking or setting if state['pre_width']: try: state['pre_width'] = int(state['pre_width']) except TypeError: print('Could not convert pre_width {} to integer'.format( repr(state['pre_width']))) return 1 # Log the state if state['verbose']: print('Running with program state:') for k, v in state.iteritems(): print('{} {}'.format(k, repr(v))) if state['list_zdf'] == 'forums': # List available zendesk forums with their IDs and titles and exit. # Listing is formatted like for following: # 12345 Category 1 name # 09876 Forum 1 name # 54321 Forum 2 name # 67890 Category 2 name if state['verbose']: print('Listing all forums') categories = zd.list_categories() for cat in categories['categories']: print('{} {}'.format(cat['id'], cat['name'])) forums = zd.list_category_forums(category_id=cat['id'])['forums'] for forum in forums: print(' {} {}'.format(forum['id'], forum['name'])) return 0 elif state['list_zdf']: if state['verbose']: print('Listing all entries in forum {}'.format(state['list_zdf'])) # List a zendesk forum's entries with their IDs and titles and exit try: forum_id = int(state['list_zdf']) except ValueError: print('Error: Could not convert to integer: {}'.format( state['list_zdf'])) return 1 entries = zd.list_topics(forum_id=state['list_zdf']) for entry in entries['topics']: print('{} {}'.format(entry['id'], entry['title'])) return 0 # Use an entries file on disk if state['json_file']: if state['verbose']: print('Reading entries from {}'.format(state['json_file'])) # Get the entries off disk with open(state['json_file'], 'r') as infile: entries = json.loads(infile.read()) else: entries = [] # Get the entries from one or more zendesk categories if state['categories']: try: cat_ids = [int(i) for i in state['categories'].split(',')] except ValueError: print('Error: Could not convert to integers: {}'.format( state['forums'])) return 1 for cat_id in cat_ids: if state['verbose']: print('Obtaining entries from category {}'.format(cat_id)) cat_entries = [] forums = zd.list_category_forums(category_id=cat_id)['forums'] for forum in forums: if state['verbose']: print('Obtaining entries from forum {}'.format( forum['id'])) # topics = [{entry}, {entry}, ..., {entry}] topics = zd.list_topics(forum_id=forum['id'])['topics'] if state['forum_sections']: cat_entries.append({ 'section': forum['name'], 'id': forum['id'], 'body': forum['description'], 'topics': topics }) # result: # cat_entries = [ # <previous forums,> # { # 'section':'FORUM TITLE', # 'topics': # [ # {entry}, # ... # {entry} # ] # } # ] else: cat_entries += topics # result: # cat_entries = [ # {entry}, # ... # {entry} # ] if state['category_sections']: cat = zd.show_category(category_id=cat_id) entries.append({ 'section': cat['name'], 'id': cat_id, 'body': cat['description'], 'topics': cat_entries }) #od[zd.show_category(category_id=cat_id)['name']] = #entries.append([zd.show_category(category_id=cat_id)['name']] = # result if forum sections: # entries = [ # <previous categories,> # { # 'section': 'CATEGORY TITLE', # 'id': 'CATEGORY ID', # 'body': 'CATEGORY DESCRIPTION', # 'topics': # [ # { # 'section':'FORUM TITLE', # 'topics': # [ # {entry}, # ... # {entry} # ] # } # ] # } # ] # # result if not forum sections: # entries = [ # <previous categories,> # { # 'section':'CATEGORY TITLE', # 'topics': # [ # {entry}, # ... # {entry} # ] # } # ] else: entries += cat_entries # result: whatever cat_entries was (forums as sections or not) # is concatenated onto the end of entries # Get the entries from one or more zendesk forums if state['forums']: try: forum_ids = [int(i) for i in state['forums'].split(',')] for forum_id in forum_ids: if state['verbose']: print('Obtaining entries from forum {}'.format(forum_id)) topics = zd.list_topics(forum_id=forum_id)['topics'] # see above for description of what entries looks like if state['forum_sections']: forum = zd.show_forum(forum_id=forum_id)['forum'] entries.append({ 'section': forum['name'], 'id': forum['id'], 'body': forum['description'], 'topics': topics }) else: entries += topics except ValueError: print('Error: Could not convert to integers: {}'.format( state['forums'])) return 1 # Get individual entries from zendesk if state['topics']: topic_ids = state['topics'].replace(' ', '') topics = zd.show_multiple_topics(topic_ids)['topics'] if state['entries_heading']: entries.append({ 'section': state['entries_heading'], 'topics': topics }) else: entries += topics if len(entries) == 0: # Didn't get entries from any inputs. print("Error: Did not receive any entries.") return 1 zdf2pdf(entries, state) if state['delete']: shutil.rmtree(state['work_dir']) return 0
def main(): arguments = docopt(__doc__) logger.setLevel(arguments['--level']) logger.debug(arguments) global cfg global run_open global open_cmd global zendesk # read in YAML configuration file if "~" in arguments['--config']: pattern = re.compile('~') arguments['--config'] = pattern.sub(os.path.expanduser("~"), arguments['--config']) if not os.path.exists(arguments['--config']): logger.error("Specified configuration file does not exist!") exit(1) with open(arguments['--config'], 'r') as ymlfile: cfg = yaml.load(ymlfile) # determine if run_open is defined and enabled try: run_open = cfg['downloader']['run_open'] if str(run_open).lower() == "true" or run_open == 1: run_open = True else: run_open = False except: run_open = False # determine if open_command is defined try: open_cmd = cfg['downloader']['open_command'] except: if run_open: logger.warning("'run_open' is set, but 'open_command' doesn't exist - disabling auto open. Please configure 'open_cmd' in .zendesk.yml.") run_open = False # check directory for downloads, expand '~' and append '/' if necessary if "~" in cfg['downloader']['directory']: pattern = re.compile('~') cfg['downloader']['directory'] = pattern.sub(os.path.expanduser("~"), cfg['downloader']['directory']) if not cfg['downloader']['directory'].endswith('/'): cfg['downloader']['directory'] += '/' logger.debug("download directory: {}".format(cfg['downloader']['directory'])) options = {} if 'extensions' in cfg['downloader']: options['extensions'] = cfg['downloader']['extensions'] if 'exclude' in cfg['downloader']: options['exclude'] = cfg['downloader']['exclude'] if 'rm_after_extract' in cfg['downloader']: options['rm_after_extract'] = cfg['downloader']['rm_after_extract'] zendesk = Zendesk(cfg['credentials']['username'], cfg['credentials']['password'], cfg['credentials']['url'], options=options) if '{0}'.format(arguments['--case']) == 'None': logger.info("No case specified, downloading attachments for all cases with updates in the last {0} hours".format(arguments['--recent'])) start_time = datetime.datetime.now() - datetime.timedelta(hours=int(arguments['--recent'])) updated_tickets = zendesk.getUpdatedTickets(start_time) logger.debug(updated_tickets) if not "error" in updated_tickets: for ticket in updated_tickets['ids']: processTicket(ticket) else: logger.error(updated_tickets['error']) else: ticket = arguments['--case'] processTicket(ticket)
from zendesk import Zendesk ################################################################ ## NEW CONNECTION CLIENT ################################################################ zendesk = Zendesk('https://yourcompany.zendesk.com', '*****@*****.**', 'passwd') # Are you getting an error such as... # "SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed"? zendesk = Zendesk('https://yourcompany.zendesk.com', '*****@*****.**', 'passwd', client_args={ "disable_ssl_certificate_validation": True } ) ################################################################ ## TICKETS ################################################################ # List zendesk.list_tickets(view_id=1) # Must have a view defined # Create new_ticket = { 'ticket': { _ 'requester_name': 'Howard Schultz', 'requester_email': '*****@*****.**', 'subject':'My Starbucks coffee is cold!', 'description': 'please reheat my coffee', 'set_tags': 'coffee drinks',
import re from zendesk import Zendesk def get_id_from_url(url): match = re.match(r".*/(?P<identifier>\d+)\.xml", url) if match and match.group('identifier'): return match.group('identifier') ################################################################ ## NEW CONNECTION CLIENT ################################################################ zendesk = Zendesk('https://yourcompany.zendesk.com', '*****@*****.**', 'passwd') ################################################################ ## TICKETS ################################################################ # List zendesk.list_tickets(view_id=1) # Must have a view defined # Create new_ticket = { 'ticket': { 'requester-name': 'Howard Schultz', 'requester-email': '*****@*****.**', 'subject': 'My Starbucks coffee is cold!', 'description': 'please reheat my coffee', 'set-tags': 'coffee drinks',
def __init__(self, settings): # Set up a set of globals to pass to every template self.gs_globals = {} # GENOMICS STATUS MAJOR VERSION NUMBER # Bump this with any change that requires an update to documentation self.gs_globals['gs_version'] = '1.0'; # Get the latest git commit hash # This acts as a minor version number for small updates # It also forces javascript / CSS updates and solves caching problems try: self.gs_globals['git_commit'] = subprocess.check_output(['git', 'rev-parse', '--short=7', 'HEAD']).strip() self.gs_globals['git_commit_full'] = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip() except: self.gs_globals['git_commit'] = 'unknown' self.gs_globals['git_commit_full'] = 'unknown' handlers = [ ("/", MainHandler), ("/login", LoginHandler), ("/logout", LogoutHandler), ("/unauthorized", UnAuthorizedHandler), ("/api/v1", DataHandler), ("/api/v1/applications", ApplicationsDataHandler), ("/api/v1/application/([^/]*)$", ApplicationDataHandler), ("/api/v1/bioinfo_analysis", BioinfoAnalysisHandler), ("/api/v1/bioinfo_analysis/([^/]*)$", BioinfoAnalysisHandler), ("/api/v1/expected", BarcodeVsExpectedDataHandler), tornado.web.URLSpec("/api/v1/caliper_image/(?P<project>[^/]+)/(?P<sample>[^/]+)/(?P<step>[^/]+)", CaliperImageHandler, name="CaliperImageHandler"), ("/api/v1/charon_summary/([^/]*)$",CharonProjectHandler ), ("/api/v1/delivered_monthly", DeliveredMonthlyDataHandler), ("/api/v1/delivered_monthly.png", DeliveredMonthlyPlotHandler), ("/api/v1/delivered_quarterly", DeliveredQuarterlyDataHandler), ("/api/v1/delivered_quarterly.png", DeliveredQuarterlyPlotHandler), ("/api/v1/flowcells", FlowcellsDataHandler), ("/api/v1/flowcell_count/", FlowcellCountApiHandler), ("/api/v1/flowcell_info2/([^/]*)$", FlowcellsInfoDataHandler), ("/api/v1/flowcell_info/([^/]*)$", OldFlowcellsInfoDataHandler), ("/api/v1/flowcell_qc/([^/]*)$", FlowcellQCHandler), ("/api/v1/flowcell_demultiplex/([^/]*)$", FlowcellDemultiplexHandler), ("/api/v1/flowcell_q30/([^/]*)$", FlowcellQ30Handler), # ("/api/v1/flowcells/([^/]*)$", FlowcellDataHandler), ("/api/v1/flowcell_notes/([^/]*)$", FlowcellNotesDataHandler), ("/api/v1/flowcell_links/([^/]*)$", FlowcellLinksDataHandler), ("/api/v1/flowcell_search/([^/]*)$", FlowcellSearchHandler), ("/api/v1/flowcell_yield/([^/]*)$", DataFlowcellYieldHandler), ("/api/v1/generate_workset", GenerateWorksetHandler), ("/api/v1/instrument_cluster_density", InstrumentClusterDensityDataHandler), ("/api/v1/instrument_cluster_density.png", InstrumentClusterDensityPlotHandler), ("/api/v1/instrument_error_rates", InstrumentErrorrateDataHandler), ("/api/v1/instrument_error_rates.png", InstrumentErrorratePlotHandler), ("/api/v1/instrument_logs", DataInstrumentLogsHandler), ("/api/v1/instrument_logs/([^/]*)$", DataInstrumentLogsHandler), ("/api/v1/instrument_names",InstrumentNamesHandler ), ("/api/v1/instrument_unmatched", InstrumentUnmatchedDataHandler), ("/api/v1/instrument_unmatched.png", InstrumentUnmatchedPlotHandler), ("/api/v1/instrument_yield", InstrumentYieldDataHandler), ("/api/v1/instrument_yield.png", InstrumentYieldPlotHandler), ("/api/v1/internal_costs/([^/]*)", ProjectInternalCostsHandler), ("/api/v1/last_updated", UpdatedDocumentsDatahandler), ("/api/v1/last_psul", LastPSULRunHandler), ("/api/v1/load_workset_samples", WorksetSampleLoadHandler), ("/api/v1/plot/q30.png", Q30PlotHandler), ("/api/v1/plot/samples_per_lane.png", SamplesPerLanePlotHandler), ("/api/v1/plot/reads_per_lane.png", ReadsPerLanePlotHandler), ("/api/v1/plot/clusters_per_lane.png", ClustersPerLanePlotHandler), ("/api/v1/plot/barcodes_vs_expected([^/]*)$", BarcodeVsExpectedPlotHandler), ("/api/v1/samples_per_lane", SamplesPerLaneDataHandler), ("/api/v1/produced_monthly", ProducedMonthlyDataHandler), ("/api/v1/produced_monthly.png", ProducedMonthlyPlotHandler), ("/api/v1/produced_quarterly", ProducedQuarterlyDataHandler), ("/api/v1/produced_quarterly.png", ProducedQuarterlyPlotHandler), ("/api/v1/projects", ProjectsDataHandler), ("/api/v1/project/([^/]*)$", ProjectSamplesDataHandler), ("/api/v1/project/([^/]*)/tickets", ProjectTicketsDataHandler), ("/api/v1/projects_fields", ProjectsFieldsDataHandler), ("/api/v1/project_summary/([^/]*)$", ProjectDataHandler), ("/api/v1/project_summary_update/([^/]*)/([^/]*)$", ProjectSummaryUpdateHandler), ("/api/v1/project_search/([^/]*)$", ProjectsSearchHandler), ("/api/v1/presets", PresetsHandler), ("/api/v1/qc/([^/]*)$", SampleQCDataHandler), ("/api/v1/projectqc/([^/]*)$", ProjectQCDataHandler), ("/api/v1/reads_vs_quality", ReadsVsQDataHandler), ("/api/v1/rna_report/([^/]*$)", ProjectRNAMetaDataHandler), ("/api/v1/running_notes/([^/]*)$", RunningNotesDataHandler), ("/api/v1/links/([^/]*)$", LinksDataHandler), ("/api/v1/sample_info/([^/]*)$", SampleInfoDataHandler), ("/api/v1/sample_readcount/(\w+)?", SampleReadCountDataHandler), ("/api/v1/sample_run_counts/(\w+)?", SampleRunReadCountDataHandler), ("/api/v1/sample_alignment/([^/]*)$", SampleQCAlignmentDataHandler), ("/api/v1/sample_coverage/([^/]*)$", SampleQCCoverageDataHandler), ("/api/v1/sample_summary/([^/]*)$", SampleQCSummaryDataHandler), ("/api/v1/sample_insert_sizes/([^/]*)$", SampleQCInsertSizesDataHandler), ("/api/v1/samples/start/([^/]*)$", PagedQCDataHandler), ("/api/v1/samples/([^/]*)$", SampleRunDataHandler), ("/api/v1/stats",StatsAggregationHandler), ("/api/v1/stats/application_open_projects",ApplicationOpenProjectsHandler), ("/api/v1/stats/application_open_samples",ApplicationOpenSamplesHandler), ("/api/v1/stats/week_instr_yield",WeekInstrumentTypeYieldHandler), ("/api/v1/stats/year_application",YearApplicationsProjectHandler), ("/api/v1/stats/year_application_samples",YearApplicationsSamplesHandler), ("/api/v1/stats/year_affiliation_projects",YearAffiliationProjectsHandler), ("/api/v1/stats/year_deliverytime_projects",YearDeliverytimeProjectsHandler), ("/api/v1/stats/year_deliverytime_application",YearDeliverytimeApplicationHandler), ("/api/v1/deliveries/set_bioinfo_responsible$", DeliveriesPageHandler), ("/api/v1/suggestions", SuggestionBoxDataHandler), ("/api/v1/test/(\w+)?", TestDataHandler), ("/api/v1/phix_err_rate", PhixErrorRateDataHandler), ("/api/v1/worksets", WorksetsDataHandler), ("/api/v1/workset/([^/]*)$", WorksetDataHandler), ("/api/v1/workset_search/([^/]*)$", WorksetSearchHandler), ("/api/v1/workset_notes/([^/]*)$", WorksetNotesDataHandler), ("/api/v1/workset_links/([^/]*)$", WorksetLinksHandler), ("/api/v1/ws_pl_to_lims", WorksetPlacementSavingHandler), ("/applications", ApplicationsHandler), ("/application/([^/]*)$", ApplicationHandler), ("/barcode_vs_expected", ExpectedHandler), ("/bioinfo/(P[^/]*)$", BioinfoAnalysisHandler), ("/deliveries", DeliveriesPageHandler), ("/clusters_per_lane", ClustersPerLaneHandler), ("/flowcells", FlowcellsHandler), ("/flowcells/([^/]*)$", FlowcellHandler), ("/flowcells_plot", FlowcellPlotHandler), ("/flowcell_count_plot", FlowcellCountPlotHandler), ("/instrument_logs",InstrumentLogsHandler), ("/instrument_logs/([^/]*)$", InstrumentLogsHandler), ("/multiqc_report/([^/]*)$", MultiQCReportHandler), ("/nas_quotas", NASQuotasHandler), ("/q30", Q30Handler), ("/qc/([^/]*)$", SampleQCSummaryHandler), (r"/qc_reports/(.*)", SafeStaticFileHandler, {"path": 'qc_reports'}), ("/quotas", QuotasHandler), ("/phix_err_rate", PhixErrorRateHandler), ("/production", ProductionHandler), ("/production/cronjobs", ProductionCronjobsHandler), ("/project/([^/]*)$", ProjectSamplesHandler), ("/project/(P[^/]*)/([^/]*)$", ProjectSamplesHandler), ("/project_summary/([^/]*)$", ProjectSummaryHandler), ("/projects/([^/]*)$", ProjectsHandler), ("/proj_meta", ProjMetaCompareHandler), ("/reads_total/([^/]*)$", ReadsTotalHandler), ("/reads_vs_qv", ReadsVsQvhandler), ("/reads_per_lane", ReadsPerLaneHandler), ("/rec_ctrl_view/([^/]*)$", RecCtrlDataHandler), ("/samples_per_lane", SamplesPerLaneHandler), ("/samples/([^/]*)$", SampleRunHandler), ("/sequencing", SequencingStatsHandler), ("/suggestion_box", SuggestionBoxHandler), ("/worksets", WorksetsHandler), ("/workset/([^/]*)$", WorksetHandler), ("/workset_placement",WorksetPlacementHandler), (r'.*', BaseHandler) ] self.declared_handlers = handlers # Load templates self.loader = template.Loader("design") # Global connection to the database couch = Server(settings.get("couch_server", None)) if couch: self.analysis_db= couch["analysis"] self.application_categories_db = couch["application_categories"] self.bioinfo_db = couch["bioinfo_analysis"] self.cronjobs_db = couch["cronjobs"] self.flowcells_db = couch["flowcells"] self.gs_users_db = couch["gs_users"] self.instruments_db= couch["instruments"] self.instrument_logs_db = couch["instrument_logs"] self.projects_db = couch["projects"] self.samples_db = couch["samples"] self.server_status_db = couch['server_status'] self.suggestions_db = couch["suggestion_box"] self.worksets_db = couch["worksets"] self.x_flowcells_db = couch["x_flowcells"] else: print settings.get("couch_server", None) raise IOError("Cannot connect to couchdb"); # Load columns and presets from genstat-defaults user in StatusDB genstat_id = '' for u in self.gs_users_db.view('authorized/users'): if u.get('key') == 'genstat-defaults': genstat_id = u.get('value') # It's important to check that this user exists! if not genstat_id: raise RuntimeError("genstat-defaults user not found on {}, please " \ "make sure that the user is abailable with the " \ "corresponding defaults information.".format(settings.get("couch_server", None))) # We need to get this database as OrderedDict, so the pv_columns doesn't # mess up user = settings.get("username", None) password = settings.get("password", None) headers = {"Accept": "application/json", "Authorization": "Basic " + "{}:{}".format(user, password).encode('base64')[:-1]} decoder = json.JSONDecoder(object_pairs_hook=OrderedDict) user_url = "{}/gs_users/{}".format(settings.get("couch_server"), genstat_id) json_user = requests.get(user_url, headers=headers).content.rstrip() self.genstat_defaults = decoder.decode(json_user) # Load private instrument listing self.instrument_list = settings.get("instruments") # If settings states mode, no authentication is used self.test_mode = settings["Testing mode"] # google oauth key self.oauth_key = settings["google_oauth"]["key"] # ZenDesk self.zendesk_url = settings["zendesk"]["url"] self.zendesk_user = settings["zendesk"]["username"] self.zendesk_token = settings["zendesk"]["token"] self.zendesk = Zendesk(self.zendesk_url, use_api_token=True, zendesk_username=self.zendesk_user, zendesk_password=self.zendesk_token, api_version=2) # Trello self.trello_api_key = settings['trello']['api_key'] self.trello_api_secret = settings['trello']['api_secret'] self.trello_token = settings['trello']['token'] # Load password seed self.password_seed = settings.get("password_seed") # load logins for the genologics sftp self.genologics_login=settings['sftp']['login'] self.genologics_pw=settings['sftp']['password'] # Location of the psul log self.psul_log=settings.get("psul_log") # index page - to display quotas of uppmax projects self.uppmax_projects = settings.get('uppmax_projects') # to display instruments in the server status self.server_status = settings.get('server_status') # project summary - multiqc tab self.multiqc_path = settings.get('multiqc_path') # Setup the Tornado Application cookie_secret = base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes) settings["debug"]= True settings["static_path"]= "static" settings["cookie_secret"]= cookie_secret settings["login_url"]= "/login" if options['develop']: tornado.autoreload.watch("design/application.html") tornado.autoreload.watch("design/applications.html") tornado.autoreload.watch("design/barcode_vs_expected.html") tornado.autoreload.watch("design/base.html") tornado.autoreload.watch("design/bioinfo_tab.html") tornado.autoreload.watch("design/bioinfo_tab/run_lane_sample_view.html") tornado.autoreload.watch("design/bioinfo_tab/sample_run_lane_view.html") tornado.autoreload.watch("design/clusters_per_lane.html") tornado.autoreload.watch("design/cronjobs.html") tornado.autoreload.watch("design/deliveries.html") tornado.autoreload.watch("design/error_page.html") tornado.autoreload.watch("design/flowcell.html") tornado.autoreload.watch("design/flowcell_error.html") tornado.autoreload.watch("design/flowcell_samples.html") tornado.autoreload.watch("design/flowcells.html") tornado.autoreload.watch("design/index.html") tornado.autoreload.watch("design/instrument_logs.html") tornado.autoreload.watch("design/link_tab.html") tornado.autoreload.watch("design/nas_quotas.html") tornado.autoreload.watch("design/phix_err_rate.html") tornado.autoreload.watch("design/production.html") tornado.autoreload.watch("design/proj_meta_compare.html") tornado.autoreload.watch("design/project_samples.html") tornado.autoreload.watch("design/project_summary.html") tornado.autoreload.watch("design/projects.html") tornado.autoreload.watch("design/q30.html") tornado.autoreload.watch("design/reads_per_lane.html") tornado.autoreload.watch("design/reads_total.html") tornado.autoreload.watch("design/reads_vs_qv.html") tornado.autoreload.watch("design/rec_ctrl_view.html") tornado.autoreload.watch("design/running_notes_help.html") tornado.autoreload.watch("design/running_notes_tab.html") tornado.autoreload.watch("design/samples_per_lane.html") tornado.autoreload.watch("design/sequencing_stats.html") tornado.autoreload.watch("design/suggestion_box.html") tornado.autoreload.watch("design/unauthorized.html") tornado.autoreload.watch("design/uppmax_quotas.html") tornado.autoreload.watch("design/workset_placement.html") tornado.autoreload.watch("design/workset_samples.html") tornado.autoreload.watch("design/worksets.html") tornado.autoreload.watch("design/yield_plot.html") tornado.web.Application.__init__(self, handlers, **settings)
def config(argv=None): import os, sys, argparse # Declare a class for an argparse custom action. # Handles converting ascii input from argparse that may contain unicode # to a real unicode string. class UnicodeStore(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, self.dest, values.decode('utf-8')) # Options precedence: # program state defaults, which are overridden by # ~/.zd.cfg [zdgrab] section options, which are overridden by # command line options, which are overridden by # -c CONFIG_FILE [zdgrab] section options, which are overridden by # ~/.zd.cfg [RUN_SECTION] section options, which are overridden by # -c CONFIG_FILE [RUN_SECTION] section options # # Program state, with defaults # state = { 'verbose': False, 'tickets': None, 'work_dir': os.path.join(os.path.expanduser('~'), 'zdgrab'), 'agent': 'me', 'url': None, 'mail': None, 'password': '******', 'is_token': False, } argp = argparse.ArgumentParser( description='Download attachments from Zendesk tickets.') argp.add_argument('-v', '--verbose', action='store_true', help='Verbose output') argp.add_argument( '-t', action=UnicodeStore, dest='tickets', help='Ticket(s) to grab attachments (default: all of your open tickets)' ) argp.add_argument('-c', action=UnicodeStore, dest='config_file', help='Configuration file (overrides ~/.zd.cfg)') argp.add_argument('-w', action=UnicodeStore, dest='work_dir', help="""Working directory in which to store attachments. (default: ~/zdgrab/)""") argp.add_argument('-a', action=UnicodeStore, dest='agent', help='Agent whose open tickets to search (default: me)') argp.add_argument('-u', action=UnicodeStore, dest='url', help='URL of Zendesk (e.g. https://example.zendesk.com)') argp.add_argument('-m', action=UnicodeStore, dest='mail', help='E-Mail address for Zendesk login') argp.add_argument('-p', action=UnicodeStore, dest='password', help='Password for Zendesk login', nargs='?', const=state['password']) argp.add_argument( '-i', '--is-token', action='store_true', dest='is_token', help='Is token? Specify if password supplied a Zendesk token') # Set argparse defaults with program defaults. # Skip password as it is argparse const, not argparse default argp.set_defaults(**dict( (k, v) for k, v in state.iteritems() if k != 'password')) # Read ~/.zd.cfg [zdgrab] section and update argparse defaults try: config_state(os.path.join(os.path.expanduser('~'), '.zd.cfg'), 'zd', state) # Password is OK now, because we either have one from the config file or # it is still None. argp.set_defaults(**dict((k, v) for k, v in state.iteritems())) except configparser.NoSectionError: # -c CONFIG_FILE did not have a [zdgrab] section. Skip it. pass # Parse the command line options if argv is None: argv = sys.argv args = argp.parse_args() # Update the program state with command line options for k in state.keys(): state[k] = getattr(args, k) # -c CONFIG_FILE given on command line read args.config_file [zdgrab], update state if args.config_file: if state['verbose']: print('Reading config file {}'.format(args.config_file)) try: config_state(args.config_file, 'zd', state) except configparser.NoSectionError: # -c CONFIG_FILE did not have a [zdgrab] section. Skip it. pass from zendesk import Zendesk if state['url'] and state['mail'] and state['password']: if state['verbose']: print( 'Configuring Zendesk with:\n' ' url: {}\n' ' mail: {}\n' ' is_token: {}\n' ' password: (hidden)\n'.format(state['url'], state['mail'], repr(state['is_token']))) zd = Zendesk(state['url'], zendesk_username=state['mail'], zendesk_password=state['password'], use_api_token=state['is_token'], api_version=2) else: msg = textwrap.dedent("""\ Error: Need Zendesk config to continue. Use -u, -m, -p options or a config file to provide the information. Config file (e.g. ~/.zd.cfg) should be something like: [zd] url = https://example.zendesk.com mail = [email protected] password = dneib393fwEF3ifbsEXAMPLEdhb93dw343 is_token = 1 agent = [email protected] """) print(msg) return 1 # Log the state if state['verbose']: print('Running with program state:') # Let's go around our ass to get to our elbow to hide the password here. for (k, v) in [(k, v) for k, v in state.iteritems() if k != 'password']: print(' {}: {}'.format(k, repr(v))) print(' password: (hidden)\n') # tickets=None means default to getting all of the attachments for this # user's open tickets. If tickets is given, try to split it into ints if state['tickets']: # User gave a list of tickets try: state['tickets'] = [int(i) for i in state['tickets'].split(',')] except ValueError: print('Error: Could not convert to integers: {}'.format( state['tickets'])) return 1 return zd, state