Example #1
0
 def getCurrentValidBatchID( self ):
     curBatch = self._auditCollection.find( { "apikey" : get_meetup_key(),
                                              "end"    : { "$type" : "date" }, #17 BSON type for timestamp
                                              "trial"  : False } ).sort( "batchID", pymongo.DESCENDING ).limit( 1 )
     
     if curBatch is None :
         raise ValueError( "No current valid batch ID" )
     else:
         try :
             x= curBatch.next()[ "batchID"]
             return x
         except StopIteration :
             raise ValueError( "Have you set a valid API key? (APIKEY='%s')" % get_meetup_key())
Example #2
0
    def __init__(self, apikey=get_meetup_key(), items=100):
        '''
        Constructor
        '''

        self._api = "https://api.meetup.com/"
        self._params = {}
        self._params["key"] = apikey
        self._items = str(items)
        self._requester = PaginatedRequest(self._items)
Example #3
0
 def testProcessMembers(self):
     self._mdb = MUGAlyserMongoDB("mongodb://localhost:27017/TESTWRITER")
     self._audit = Audit(self._mdb)
     batchID = self._audit.start_batch({"test": 2})
     self._writer = MeetupWriter(get_meetup_key(), batchID, self._mdb)
     self._writer.write_members("pro", ["DublinMUG"])
     self._writer.write_members("nopro", ["DublinMUG"])
     self.assertTrue(self._mdb.proMembersCollection().find_one(
         {"member.member_name": "Joe Drumgoole"}))
     self.assertTrue(self._mdb.membersCollection().find_one(
         {"member.name": "Joe Drumgoole"}))
     self._audit.end_batch(batchID)
Example #4
0
 def test_write_group(self):
     self._mdb = MUGAlyserMongoDB("mongodb://localhost:27017/TESTWRITER")
     self._audit = Audit(self._mdb)
     batchID = self._audit.start_batch({"test": 1})
     self._writer = MeetupWriter(get_meetup_key(), batchID, self._mdb)
     self._writer.write_groups("nopro", ["DublinMUG"])
     self._writer.write_groups("pro", ["DublinMUG"])
     self.assertTrue(self._mdb.groupsCollection().find_one(
         {"group.urlname": "DublinMUG"}))
     self.assertTrue(self._mdb.proGroupsCollection().find_one(
         {"group.urlname": "DublinMUG"}))
     self._audit.end_batch(batchID)
Example #5
0
    def getCurrentValidBatches( self, start=None, end=None ):
        
        agg = Agg( self._auditCollection )
        agg.addMatch({ "apikey" : get_meetup_key(),
                       "end"    : { "$ne" : None },
                       "trial"  : False }  )
        
        agg.addRangeMatch( "start", start, end)
        agg.addSort( Sorter( batchID = pymongo.DESCENDING ))
        
#         cursor = self._auditCollection.find( { "apikey" : get_meetup_key(),
#                                                "end"    : { "$ne" : None },
#                                                "trial"  : False } ).sort( "batchID", pymongo.DESCENDING )
                                         
        return agg
Example #6
0
    def __init__(self, audit, mdb, urls, apikey= get_meetup_key(), unordered=True ):
        '''
        Write contents of meetup API to MongoDB
        '''

        self._mdb = mdb
        self._meetup_api = MeetupAPI( apikey )
        self._audit = audit
        self._groups = self._mdb.groupsCollection()
        self._members = self._mdb.membersCollection()
        self._attendees = self._mdb.attendeesCollection()
        self._pastEvents = self._mdb.pastEventsCollection()
        self._upcomingEvents = self._mdb.upcomingEventsCollection()
        self._mugs = []
        self._unordered = unordered
        self._urls = urls
Example #7
0
 def startBatch(self, doc, name=None, trial=False, apikey = get_meetup_key()):
     thisBatchID = self.incrementBatchID()
     
     if name is None :
         name = "Standard Batch: %i" % thisBatchID
         
     self._auditCollection.insert_one( { "batchID" : thisBatchID,
                                         "start"   : datetime.now(),
                                         "trial"   : trial,
                                         "end"     : None,
                                         "name"    : name,
                                         "apikey"  : apikey,
                                         "info"    : doc })
     
     self._currentBatchID = thisBatchID
     
     return thisBatchID
Example #8
0
    def test_getCurrentValidBatchID(self):
        batchID1 = self._audit.startBatch(doc={"test": "doc"}, trial=True)
        self._audit.endBatch(batchID1)
        #self.assertRaises( ValueError, self._audit.getCurrentValidBatchID )

        batchID2 = self._audit.startBatch(
            {
                "args": "arg list",
                "version": __programName__ + " " + __version__
            },
            trial=False,
            apikey=get_meetup_key())

        self._audit.endBatch(batchID2)
        self.assertEqual(batchID2, self._audit.getCurrentValidBatchID())

        batchID3 = self._audit.startBatch(doc={"test": "doc"}, trial=True)
        self._audit.endBatch(batchID3)
        self.assertEqual(batchID2, self._audit.getCurrentValidBatchID())
Example #9
0
    def test_api_fail(self):
        params={}
        params[ "key" ] = get_meetup_key()
        #params[ "group_urlname" ] = "MongoDBGlasgow"
        params[ "group_urlname" ] = "London-MongoDB-User-Group"
        params[ "page"]    = 10
        count = 0
        print( "requests.get(%s, %s)" % ( "https://api.meetup.com/2/members", params ))
        r = requests.get( "https://api.meetup.com/2/members", params )
        count = count + 1 
        print( "requests count : %i" % count )
        print( r.url )
        _ = r.headers
        body = r.json()
        
        print( "results: %i" % len( body[ "results"]))
        for i in body[ "results"]:
            #print( i )
            pass
    
        #print( body[ "meta"])
        
        while ( body[ 'meta' ][ "next" ] != ""  ) :

            print( "requests.get(%s)" % body['meta'][ 'next' ] )
            r = requests.get( body['meta'][ 'next' ] )
            count = count + 1 
            print( "requests count : %i" % count )
            print( "next: %s" % r.url )
            print( "body: '%s'" % r.text )

            body = r.json()
            print( "results: %i" % len( body ))
        
            for i in body[ "results"]:
                #print( i )
                pass
Example #10
0
def main(argv=None):  # IGNORE:C0111
    '''Command line options.'''

    if argv:
        sys.argv.extend(argv)

    try:
        # Setup argument parser

        parser = ArgumentParser(description='''
Read data from the Meetup API and write it do a MongoDB database. Each run of this program
creates a new batch of data identified by a batchID. The default database is MUGS. You can change
this by using the --host parameter and specifying a different database in the mongodb URI.
If you use the --pro arguement your API key must be a meetup pro account API key. If not the api
calls to the pro interface will fail.

If you are and adminstrator on the pro account you should use the --admin flag to give you
access to the admin APIs.
''')
        #
        # MongoDB Args

        parser.add_argument('--host',
                            default="mongodb://localhost:27017/MUGS",
                            help='URI to connect to : [default: %(default)s]')

        parser.add_argument("--verbose",
                            dest="verbose",
                            action="count",
                            help="set verbosity level [default: %(default)s]")
        parser.add_argument("-v",
                            "--version",
                            action='version',
                            version=__programName__ + " " + __version__)
        parser.add_argument(
            '--trialrun',
            action="store_true",
            default=False,
            help='Trial run, no updates [default: %(default)s]')

        parser.add_argument(
            '--mugs',
            nargs="+",
            help='Process MUGs list list mugs by name [default: %(default)s]')

        parser.add_argument(
            "--pro",
            default=False,
            action="store_true",
            help="use if you have a pro account uses pro API calls")
        parser.add_argument(
            "--admin",
            default=False,
            action="store_true",
            help="Some calls are only available to admin users")
        parser.add_argument(
            "--database",
            default="MUGS",
            help="Default database name to write to [default: %(default)s]")
        parser.add_argument('--phases',
                            nargs="+",
                            choices=[
                                "groups", "members", "attendees",
                                "upcomingevents", "pastevents"
                            ],
                            default=["all"],
                            help='execution phases')

        parser.add_argument(
            '--loglevel',
            default="INFO",
            choices=["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
            help='Logging level [default: %(default)s]')

        parser.add_argument('--apikey',
                            default=None,
                            help='Default API key for meetup')

        parser.add_argument(
            '--urlfile',
            help=
            "File containing a list of MUG URLs to be used to parse data [ default: %(default)s]"
        )
        # Process arguments
        args = parser.parse_args()

        apikey = ""

        if args.apikey:
            apikey = args.apikey
        else:
            apikey = get_meetup_key()

        verbose = args.verbose

        format_string = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        logging.basicConfig(format=format_string,
                            level=LoggingLevel(args.loglevel))

        # Turn off logging for requests
        logging.getLogger("requests").setLevel(logging.WARNING)
        logging.getLogger("urllib3").setLevel(logging.WARNING)

        if verbose > 0:
            logging.info("Verbose mode on")

        if args.urlfile:
            if not os.path.isfile(args.urlfile):
                print("No such file --urlfile '%s'" % args.urlfile)
                sys.exit(1)

        if args.mugs:
            mugList = args.mugs
        else:
            mugList = []

        if args.pro:
            nopro = False
        else:
            nopro = True

        mdb = MUGAlyserMongoDB(args.host)

        audit = Audit(mdb)

        batchID = audit.startBatch(
            {
                "args": vars(args),
                "version": __programName__ + " " + __version__,
                "pro_account": args.pro
            },
            trial=args.trialrun,
            apikey=apikey)

        start = datetime.utcnow()
        logging.info("Started MUG processing for batch ID: %i", batchID)
        logging.info("Writing to database : '%s'", mdb.database().name)
        if nopro:
            logging.info("Using standard API calls (no pro account API key)")
            if args.urlfile:
                logging.info("Reading groups from: '%s'", args.urlfile)
                with open(args.urlfile) as f:
                    mugList = f.read().splitlines()

        else:
            logging.info("Using pro API calls (pro account API key)")

        if nopro:
            logging.info("Processing %i MUG URLS", len(mugList))
        else:
            mugList = list(MeetupAPI().get_pro_group_names())

        writer = MeetupWriter(audit, mdb, mugList, apikey)

        if "all" in args.phases:
            phases = ["groups", "members", "upcomingevents", "pastevents"]
            if args.admin:
                phases.append("attendees")
        else:
            phases = args.phases

        if "groups" in phases:
            logging.info("processing group info for %i groups: nopro=%s",
                         len(mugList), nopro)
            writer.processGroups(nopro)
            phases.remove("groups")
        if "members" in phases:
            logging.info("processing members info for %i groups: nopro=%s",
                         len(mugList), nopro)
            writer.processMembers(nopro)
            phases.remove("members")

        for i in mugList:
            writer.capture_snapshot(i, args.admin, phases)

        audit.endBatch(batchID)
        end = datetime.utcnow()

        elapsed = end - start

        logging.info("MUG processing took %s for BatchID : %i", elapsed,
                     batchID)

    except KeyboardInterrupt:
        print("Keyboard interrupt : Exiting...")
        sys.exit(2)

    except pymongo.errors.ServerSelectionTimeoutError, e:
        print("Failed to connect to MongoDB Server (server timeout): %s" % e)
        sys.exit(2)
Example #11
0
 def setUp(self):
     apikey = get_meetup_key()
     self._api = MeetupAPI(apikey, reshape=True)
Example #12
0
def apikey():
    get_dns_name()
    with cd( "GIT/MUGAlyser/mugalyser") :
        run( "python makeapikeyfile_main.py %s" % get_meetup_key())
Example #13
0
def main():
    try:
        parser = ArgumentParser(
            description="A direct interface to the meetup API")

        parser.add_argument("--apikey",
                            default="",
                            help="API Key to use for Calls")
        parser.add_argument("-i",
                            "--member_id",
                            type=int,
                            help="Retrieve information for a specific ID")
        parser.add_argument("-g", "--mugs", nargs="+", help="Get Info for MUG")
        parser.add_argument("--members",
                            default=False,
                            action="store_true",
                            help="list all members of a list of groups")
        parser.add_argument("-l",
                            "--listgroups",
                            action="store_true",
                            default=False,
                            help="List all groups")
        parser.add_argument("--groups",
                            default=False,
                            action="store_true",
                            help="list group data for groups")
        parser.add_argument(
            "--allgroups",
            default=False,
            action="store_true",
            help="list group data for all groups for this API key")
        parser.add_argument(
            "--progroups",
            default=False,
            action="store_true",
            help="list group data for all pro groups for this API key")
        parser.add_argument("-u",
                            "--urlnames",
                            action="store_true",
                            default=False,
                            help="List all groups by URL name")
        parser.add_argument("--pastevents",
                            nargs="+",
                            default=[],
                            help="Get past events for MUG")
        parser.add_argument("--upcomingevents",
                            nargs="+",
                            default=[],
                            help="Get upcoming events for MUG")
        parser.add_argument("--attendees",
                            nargs="+",
                            default=[],
                            help="Get attendees for list of groups")
        parser.add_argument("--loop",
                            type=int,
                            default=1,
                            help="Loop call for --loop times")
        parser.add_argument("--reshape",
                            default=False,
                            action="store_true",
                            help="Reshape output for BSON")
        parser.add_argument("--req",
                            default=False,
                            action="store_true",
                            help="Report underlying request URL to meetup")
        # Process arguments
        args = parser.parse_args()

        format_string = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        logging.basicConfig(format=format_string, level=logging.INFO)
        if args.apikey == "":
            m = MeetupAPI(apikey=get_meetup_key(), reshape=args.reshape)
        else:
            m = MeetupAPI(apikey=args.apikey, reshape=args.reshape)

        for i in range(args.loop):
            if args.member_id and not (args.progroups or args.allgroups):
                (url, member) = m.get_member_by_id(args.member_id)
                if args.req:
                    print("req: '{}'".format(url))
                pprint.pprint(member)

            if args.allgroups:
                member_total = 0
                for group_count, g in enumerate(m.get_groups(), 1):
                    #pprint.pprint(g)
                    #print(f"{g[1]['urlname']}")
                    group = g[1]
                    full_group = m.get_group(group['urlname'])[1]
                    if full_group["organizer"]["id"] == args.member_id:
                        pprint.pprint(full_group)
                        print(
                            f"{full_group['urlname']}, {full_group['members']}"
                        )
                        member_total = member_total + full_group['members']
                print(f"{group_count} groups in total")
                print(f"Total members: {member_total}")

            if args.progroups:
                member_total = 0
                group_count = 0
                for url, g in m.get_groups():
                    print(f"URL   :{url}")
                    pprint.pprint(g)
                    #print(f"{g[1]['urlname']}")
                    group = g
                    url, full_group = m.get_group(group['urlname'])
                    if "pro_network" in full_group and full_group[
                            "pro_network"]["name"] == "MongoDB":
                        #pprint.pprint(full_group)
                        print(
                            f"{full_group['urlname']}, {full_group['members']}"
                        )
                        member_total = member_total + full_group['members']
                        group_count = group_count + 1
                print(f"{group_count} groups in total")
                print(f"Total members: {member_total}")
            if args.groups:
                for i in args.mugs:
                    (url, mug) = m.get_group(i)
                    if args.req:
                        print("req: '{}'".format(url))
                    pprint.pprint(mug)

            if args.members:
                print("args.members: %s" % args.mugs)
                # it = m.get_members( args.mugs )

                count = 0
                name = ""
                mid = ""
                for (url, j) in m.get_members(args.mugs):
                    if args.req:
                        print("req: '{}'".format(url))
                    count = count + 1

                    if "name" in j:
                        name = j["name"]
                        mid = j["id"]
                    else:
                        name = j["member_name"]
                        mid = j["member_id"]
                    print(u"{:30}, {:20}, {:20}, {:20}".format(
                        name, i, j["country"], mid))

                print("%i total" % count)

            if args.pastevents:
                (url, past_events) = m.get_past_events(args.pastevents)
                if args.req:
                    print("req: '{}'".format(url))
                printCursor(past_events)

            if args.upcomingevents:
                (url,
                 upcoming_events) = m.get_upcoming_events(args.upcomingevents)
                if args.req:
                    print("req: '{}'".format(url))
                printCursor(upcoming_events)

            if args.attendees:
                attendees = m.get_all_attendees(args.attendees)
                printCursor(attendees)

            if args.listgroups:
                printCursor(m.get_pro_groups())

            if args.urlnames:
                for i in m.get_pro_group_names():
                    print(i)

    except KeyboardInterrupt:
        print("Keyboard interrupt : Exiting...")
        sys.exit(2)

    except Exception as e:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        print_exception(exc_type, exc_value, exc_traceback)
        indent = len("mug_info_main") * " "
        sys.stderr.write("mug_info_main" + ": " + repr(e) + "\n")
        sys.stderr.write(indent + "  for help use --help\n")
        return 2

    return 0
Example #14
0
def mugalyser(argv=None):  # IGNORE:C0111
    '''Command line options.'''

    try:
        # Setup argument parser

        parser = ArgumentParser(description='''
Read data from the Meetup API and write it do a MongoDB database. Each run of this program
creates a new batch of data identified by a batchID. The default database is MUGS. You can change
this by using the --host parameter and specifying a different database in the mongodb URI.
If you use the --pro arguement your API key must be a meetup pro account API key. If not the api
calls to the pro interface will fail.

If you are and adminstrator on the pro account you should use the --admin flag to give you
access to the admin APIs.
''')
        #
        # MongoDB Args

        parser.add_argument('--host',
                            default="mongodb://localhost:27017/MUGS",
                            help='URI to connect to : [default: %(default)s]')
        parser.add_argument("-v",
                            "--version",
                            action='version',
                            version=__programName__ + " " + __version__)
        parser.add_argument(
            '--mugs',
            nargs="+",
            default=[],
            help='Process MUGs list list mugs by name [default: %(default)s]')

        parser.add_argument("--collect",
                            choices=["pro", "nopro", "all"],
                            default="all",
                            help="Use pro API calls, no pro API calls or both")
        parser.add_argument(
            "--admin",
            default=False,
            action="store_true",
            help=
            "Some calls are only available to admin users, use this if you are not an admin"
        )
        parser.add_argument(
            "--database",
            default="MUGS",
            help="Default database name to write to [default: %(default)s]")
        parser.add_argument('--phases',
                            nargs="+",
                            choices=[
                                "groups", "members", "attendees",
                                "upcomingevents", "pastevents"
                            ],
                            default=["all"],
                            help='execution phases')

        parser.add_argument(
            '--loglevel',
            default="INFO",
            choices=["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
            help='Logging level [default: %(default)s]')

        parser.add_argument('--apikey',
                            default=None,
                            help='Default API key for meetup')

        parser.add_argument("--batchname",
                            default=__programName__,
                            help="Batch name used in creating audit batches")
        parser.add_argument(
            '--urlfile',
            help=
            "File containing a list of MUG URLs to be used to parse data [ default: %(default)s]"
        )
        parser.add_argument(
            "--drop",
            default=False,
            action="store_true",
            help="drop the database before writing data [default: %(default)s]"
        )
        parser.add_argument("--organizer_id",
                            type=int,
                            help="Organizer ID is required for non pro groups")
        # Process arguments
        args = parser.parse_args(argv)

        apikey = ""

        if args.apikey:
            apikey = args.apikey
        else:
            apikey = get_meetup_key()

        mugalyser_logger = Logger(__programName__, args.loglevel)
        # mugalyser_logger.add_stream_handler( args.loglevel )
        mugalyser_logger.add_file_handler("mugalyser.log", args.loglevel)

        api = MeetupAPI(apikey, reshape=True)
        logger = mugalyser_logger.log()

        # Turn off logging for requests
        logging.getLogger("requests").setLevel(logging.WARNING)
        logging.getLogger("urllib3").setLevel(logging.WARNING)

        mdb = MUGAlyserMongoDB(uri=args.host, database_name=args.database)

        if args.drop:
            logger.warn(f"Dropping database:'{args.database}'")
            mdb.drop(args.database)

        audit = Audit(mdb)

        batchID = audit.start_batch({
            "args": vars(args),
            "version": __programName__ + " " + __version__,
            "name": args.batchname
        })

        start = datetime.utcnow()
        logger.info("Started MUG processing for batch ID: %i", batchID)
        logger.info("Writing to database : '%s'", mdb.database().name)

        group_dict = {}

        count = 0
        group_list = []
        if args.mugs:
            for url in args.mugs:
                group_list.append(api.get_group(url))
        else:
            group_list = list(api.get_groups())

        for url, group in group_list:

            #print(f"Checking:{group['urlname']}")
            urlname = group['urlname']
            url, full_group = api.get_group(urlname)
            if args.collect in ["pro", "all"]:
                if "pro_network" in full_group and full_group["pro_network"][
                        "name"] == "MongoDB":
                    count = count + 1
                    logger.info(
                        f"{count}. Processing pro group: {group['urlname']}")
                    group_dict[urlname] = full_group

            if args.collect in ["nopro", "all"]:
                if args.organizer_id:
                    if full_group["organizer"]["id"] == args.organizer_id:
                        count = count + 1
                        logger.info(
                            f"{count}. Processing normal group: {group['urlname']}"
                        )
                        group_dict[urlname] = full_group
                else:
                    logger.error(
                        "You must specify --organizer_id  when collecting nopro groups"
                    )
                    sys.exit(1)

        if args.urlfile:
            urlfile = os.path.abspath(args.urlfile)
            logger.info("Reading groups from: '%s'", urlfile)
            with open(urlfile) as f:
                lines = f.read().splitlines()
                # string comments
                regex = "^\s*#.*|^\s*$"  # comments with # or blank lines
                for i in lines:
                    clean_line = i.rstrip()
                    if not re.match(regex, clean_line):
                        group_dict[clean_line] = None

        # scoop up any command line args
        for i in args.mugs:
            group_dict[i] = None

        writer = MeetupWriter(apikey, batchID, mdb, reshape=True)

        if "all" in args.phases:
            phases = ["groups", "members", "upcomingevents", "pastevents"]

        else:
            phases = args.phases

        if args.admin:
            logger.info("--admin : we will collect attendee info")
            phases.append("attendees")
        else:
            logger.info("No admin account")
            logger.info(
                "We will not collect attendee info: ignoring attendees")

        logger.info("Processing phases: %s", phases)

        if "groups" in phases:
            logger.info("processing group info for %i groups: collect=%s",
                        len(group_dict), args.collect)
            writer.write_groups(group_dict.keys())
            phases.remove("groups")
        if "members" in phases:
            logger.info("processing members info for %i groups: collect=%s",
                        len(group_dict), args.collect)
            writer.write_members(group_dict.keys())
            phases.remove("members")

        for i in group_dict.keys():
            writer.capture_snapshot(i, args.admin, phases)

        audit.end_batch(batchID)
        end = datetime.utcnow()

        elapsed = end - start

        logger.info("MUG processing took %s for BatchID : %i", elapsed,
                    batchID)

    except KeyboardInterrupt:
        print("Keyboard interrupt : Exiting...")
        sys.exit(2)

    except pymongo.errors.ServerSelectionTimeoutError as e:
        print("Failed to connect to MongoDB Server (server timeout): %s" % e)
        sys.exit(2)