def deleteEvent(self, event): logging.debug('Discourse') dateTimeFormat = '%Y %b %d - %I:%M %p' description = event.htmlSummary() logging.debug('Connecting to API') discourse_api = DiscourseClient( self.getSetting('Website'), api_username=self.getSetting('Username'), api_key=self.getSetting('API Key')) logging.debug('Deleting post') title = 'Event notice: ' + event.title + ' (' \ + event.start_date.strftime(dateTimeFormat) + ')' post_id = event.getExternalEventByPlatformName(self.name).ext_event_id try: post = discourse_api.update_post(post_id=post_id, content=description, category_id=int(self.getSetting('Category ID')), topic_id=None, title=title) except DiscourseClientError as err: if err.__str__() == "The requested URL or resource could not be found.": # Looks like the post is already gone return else: raise topic_id = post['post']['topic_id'] discourse_api.delete_topic(topic_id=topic_id)
def create_post(user, post_details, category_id=None, topic_id=None): """Call discourse API posts.json to create a new Topic or Post within a topic """ logger.info('+ discourse.create_post') if not user.is_authenticated: return True, 'Please logon to Post to Discourse', 0, '' # Create Discourse client for user client = DiscourseClient( settings.DISCOURSE_HOST, api_username=user.username, api_key=settings.DISCOURSE_API_KEY) # Check user is present in Discourse error, error_message, user_id = get_user(client, user.username) if user_id == 0: return error, error_message, 0, '' title = post_details['title'] content = post_details['content'] tags = post_details['tags'] if tags is None: tags = [] if len(content) < 20: return True, 'Content must be more than 20 characters long in Discourse', 0, '' post = client.create_post(content, category_id, topic_id, title, tags) # posts url = / t / {topic_id} / {post_number} post_url = os.path.join(settings.DISCOURSE_HOST, 't', str(post['topic_id']), str(post['post_number'])) logger.info('- discourse.create_post') return error, error_message, post['topic_id'], post_url
def updateEvent(self, event): logging.debug('Discourse') dateTimeFormat = '%Y %b %d - %I:%M %p' description = event.htmlSummary() logging.debug('Connecting to API') discourse_api = DiscourseClient( self.getSetting('Website'), api_username=self.getSetting('Username'), api_key=self.getSetting('API Key')) logging.debug('Updating post') title = 'Event notice: ' + event.title + ' (' \ + event.start_date.strftime(dateTimeFormat) + ')' post_id = next(item.ext_event_id for item in event.external_events if item.platformName() == self.name) try: discourse_api.update_post(post_id=post_id, content=description, category_id=int(self.getSetting('Category ID')), topic_id=None, title=title) except DiscourseClientError as err: if err.__str__() == "The requested URL or resource could not be found.": return False else: raise return True
def main(): logging.basicConfig(format="%(asctime)s - %(levelname)s: %(message)s", level=logging.INFO) assert DISCOURSE_CREDENTIALS[ "api_key"], "Environment variable DISCOURSE_API_KEY not set" parser = argparse.ArgumentParser( description= 'Updates voucher post, sends out vouchers via PM, receives returned vouchers via PM' ) parser.add_argument('--dry', action='store_true', help='do not execute POST or PUT requests') parser.add_argument('--broadcast', type=str, help='send a message to all voucher owners') args = parser.parse_args() client = DiscourseClient(**DISCOURSE_CREDENTIALS) if args.dry: disable_request(client, 'POST') disable_request(client, 'PUT') test_login(client) vouchers = read_voucher_config() for voucher in vouchers: if not voucher['owner']: continue if voucher.get('message_id'): new_voucher_code = check_for_returned_voucher(client, voucher) if new_voucher_code: logging.info(f'Voucher returned by {get_username(voucher)}') send_message_to_user( client, voucher, message=f'Prima, vielen Dank für "{new_voucher_code}"!') voucher['voucher'] = new_voucher_code voucher['owner'] = None voucher['message_id'] = None voucher['persons'] = None if args.broadcast: send_message_to_user(client, voucher, message=args.broadcast) else: send_voucher_to_user(client, voucher) post_content = render('voucher_table.md', vouchers=vouchers) client.update_post(VOUCHER_TABLE_POST_ID, post_content) if args.dry: logging.info( f'Dry run: Config written to voucher_dryrun.yml instead of {VOUCHER_CONFIG_PATH}' ) write_voucher_config(vouchers, 'voucher_dryrun.yml') else: write_voucher_config(vouchers)
def send_message_to_user(client: DiscourseClient, voucher: VoucherConfigElement, message: str) -> None: username = get_username(voucher) message_id = voucher.get('message_id') if not message_id: return logging.info(f'Sending message to {username} (Thread {message_id})') client.create_post(message, topic_id=message_id)
def process_category (category_details): """Check category is present in Table - If not create it in Discourse and store the id returned.. """ # DISCOURSE_DEV_POST_SUFFIX is used to differentiate the same target name from different dev systems in Discourse # It is not intended to be used for production when there is a dedicated Discourse. category_name = category_details['category_name'] + settings.DISCOURSE_DEV_POST_SUFFIX # Create Discourse client for fragalysis user client = DiscourseClient( settings.DISCOURSE_HOST, api_username=settings.DISCOURSE_USER, api_key=settings.DISCOURSE_API_KEY) try: category = DiscourseCategory.objects.get(category_name=category_name) category_id = category.discourse_category_id post_url = os.path.join(settings.DISCOURSE_HOST, 'c', str(category_id)) except DiscourseCategory.DoesNotExist: category_id, post_url = create_category(client, category_name, category_details['parent_name'], category_details['category_colour'], category_details['category_text_colour']) DiscourseCategory.objects.create(category_name=category_name, discourse_category_id=category_id) return category_id, post_url
def list_discourse_posts_for_topic(topic_title): """Call discourse APIs to retreive posts for the given topic Makes the translation from Fragalysis topic_name to discourse id. :param topic_title :return: error or json of posts. """ print('+ discourse.get_discourse_posts_for_topic') posts = '' error = False # DISCOURSE_DEV_POST_SUFFIX is used to differentiate the same target name from different dev systems in Discourse # It is not intended to be used for production when there is a dedicated Discourse. if topic_title: topic_title = topic_title + settings.DISCOURSE_DEV_POST_SUFFIX # Get topic_id for title try: topic = DiscourseTopic.objects.get(topic_title=topic_title) except DiscourseTopic.DoesNotExist: topic = None if topic: # Create Discourse client client = DiscourseClient( settings.DISCOURSE_HOST, api_username=settings.DISCOURSE_USER, api_key=settings.DISCOURSE_API_KEY) posts = topic_posts(client, topic.discourse_topic_id) else: error = True print('- discourse.get_discourse_posts_for_topic') return error, posts
def list_discourse_posts_for_topic(topic_title): """Call discourse APIs to retreive posts for the given topic Makes the translation from Fragalysis topic_name to discourse id. :param topic_title :return: error or json of posts. """ print('+ discourse.get_discourse_posts_for_topic') posts = '' error = False # Get topic_id for title try: topic = DiscourseTopic.objects.get(topic_title=topic_title) except DiscourseTopic.DoesNotExist: topic = None if topic: # Create Discourse client client = DiscourseClient(settings.DISCOURSE_HOST, api_username=settings.DISCOURSE_USER, api_key=settings.DISCOURSE_API_KEY) posts = topic_posts(client, topic.discourse_topic_id) else: error = True print('- discourse.get_discourse_posts_for_topic') return error, posts
def _auth_discourse_server(self): """Authenticate to Discourse This uses the API_SITE, API_USER, and API_KEY env vars. """ # Load the config, so we can store secrets outside of env vars config = load_config() in_conf = "discourse" in config # Load the needed secrets either from the config file if it exists # or the env var if it's defined (which takes precedence) site = getenv("DISCOURSE_API_SITE") or (in_conf and config["discourse"]["site"]) user = getenv("DISCOURSE_API_USER") or (in_conf and config["discourse"]["user"]) key = getenv("DISCOURSE_API_KEY") or (in_conf and config["discourse"]["key"]) for envvar in [site, user, key]: if not envvar: raise ValueError("DISCOURSE_API_SITE, DISCOURSE_API_USER, and", "DISCOURSE_API_KEY must be defined") # Authenticate to the server server = DiscourseClient(site, api_username=user, api_key=key) return server
def Setup(self): self.WA_API = WaApiClient() while (not self.WA_API.ConnectAPI(self.config.get('api', 'key'))): time.sleep(5) self.processed_filename = "followup_processed.txt" self.discourse_api = DiscourseClient( self.config.get('discourse_api', 'site'), api_username=self.config.get('discourse_api', 'username'), api_key=self.config.get('discourse_api', 'key')) self.member_levels = [ 'Monthly', '6 months', '12 months', "Scholarship (monthly)", "Scholarship (6 months)", "Scholarship (12 months)" ] self.group_name = 'MakeICT_Members' self.member_group_id = \ self.discourse_api._get("/groups/{0}.json".format(self.group_name))['group']['id']
def __init__(self, feature, metrics): self.feature = feature self.metrics = metrics client = DiscourseClient( host="https://{}".format(os.environ.get("DISCOURSE_DOMAIN_NAME")), api_username=os.environ.get("DISCOURSE_CLIENT_API_USERNAME"), api_key=os.environ.get("DISCOURSE_CLIENT_API_TOKEN")) self.client = client
def send_voucher_to_user(client: DiscourseClient, voucher: VoucherConfigElement): username = get_username(voucher) message_content = render('voucher_message.md', voucher=voucher) logging.info(f'Sending voucher to {username}') res = client.create_post(message_content, title='Dein 36C3 Voucher', archetype='private_message', target_usernames=username) message_id = res.get('topic_id') logging.info(f'Sent, message_id is {message_id}') voucher['message_id'] = message_id
def check_for_returned_voucher(client: DiscourseClient, voucher: VoucherConfigElement) -> Optional[str]: message_id = voucher['message_id'] posts = client.posts(message_id) user_posts = [ post for post in posts['post_stream']['posts'] if post['name'] != 'flipbot' ] user_posts_content = ' '.join([p['cooked'] for p in user_posts]) new_voucher = re.search(r'CHAOS[a-zA-Z0-9]+', user_posts_content) if new_voucher: return new_voucher[0]
def disable_request(client: DiscourseClient, disable_verb: Optional[str] = None, disable_path: Optional[str] = None): original_request = client._request def new_request_fn(verb, path, *args, **kwargs): if disable_verb and verb == disable_verb or disable_path and path == disable_path: logging.info( f'Dry run. {verb} request to {path} was not made. Data:') logging.info(kwargs.get('data')) return {} return original_request(verb, path, *args, **kwargs) client._request = new_request_fn
def createEvent(self, event): logging.debug('Discourse') dateTimeFormat = '%Y %b %d - %I:%M %p' description = event.htmlSummary() logging.debug('Connecting to API') discourse_api = DiscourseClient( self.getSetting('Website'), api_username=self.getSetting('Username'), api_key=self.getSetting('API Key')) logging.debug('Creating post') title = 'Event notice: ' + event.title + ' (' \ + event.start_date.strftime(dateTimeFormat) + ')' post = discourse_api.create_post(content=description, category_id=int(self.getSetting('Category ID')), topic_id=None, title=title) post_url = f"https://talk.makeict.org/t/{post['id']}" return (post['id'], post_url)
def check_discourse_user(user): """Call discourse API to check discourse user exists """ # Create Discourse client for user client = DiscourseClient( settings.DISCOURSE_HOST, api_username=user.username, api_key=settings.DISCOURSE_API_KEY) # Check user is present in Discourse error, error_message, user_id = get_user(client, user.username) if user_id == 0: return error, error_message, 0 return error, error_message, user_id
def create_discourse_post(user, category_details=None, post_details=None): """Call discourse APIs to create the category, topic or post details as requested Makes the translation from Fragalysis topic_name to discourse id. :param user :param category_details (optional) (name=<target name required>, color=<hex> (optional defaults), text_color=<hex> (optional defaults), parent_category_name=<parent category> (initially can default to “Fragalysis targets” (this is a setting) :param post_details (optional) {title=<e.g session-project.name required>, content=<e.g session-project.description, created_date=<date>, tags[list]} :return: error or url of post. """ logger.info('+ discourse.create_discourse_post') error = False post_url = '' if category_details is None and post_details is None: # Nothing to post return True if user is None: # User is not logger on return True category_id = 0 # If category details exist then create/return the category using the fragalysis user if category_details: category_id, post_url = process_category(category_details) # If post details exist then create the post if post_details: # Create Discourse client for user client = DiscourseClient(settings.DISCOURSE_HOST, api_username=user.username, api_key=settings.DISCOURSE_API_KEY) # Check user is present in Discourse user_id = get_user(client, user.username) if user_id == 0: return True topic_id, post_url = process_post(client, category_id, post_details, user) logger.info('- discourse.create_discourse_post') return error, post_url
def run(self): try: from pydiscourse import DiscourseClient except ImportError as ie: print "--> pip install pydiscourse <--" raise ie client = DiscourseClient('https://discourse.corda.net', api_username='******', api_key=secrets.DISCOURSE_API_KEY) def old_way(): usernames = set() more = "/directory_items?period=all" while (more): stuff = client._get(more) for di in stuff["directory_items"]: usernames.add(di["user"]["username"]) if len(stuff["directory_items"] ) and "load_more_directory_items" in stuff: more = stuff["load_more_directory_items"] else: more = None def get_number_of_posts(client): categories = { x['id']: x['post_count'] for x in client._get("/categories")["category_list"] ["categories"] } return sum(categories.values()) def get_number_of_users(client): stuff = client._get("/directory_items?period=all") return stuff["total_rows_directory_items"] return { "discourse_user_count": get_number_of_users(client), "discourse_number_of_posts": get_number_of_posts(client) }
def process_category(category_details): """Check category is present in Table - If not create it in Discourse and store the id returned.. """ post_url = '' # Create Discourse client for fragalysis user client = DiscourseClient(settings.DISCOURSE_HOST, api_username=settings.DISCOURSE_USER, api_key=settings.DISCOURSE_API_KEY) try: category = DiscourseCategory.objects.get( category_name=category_details['category_name']) category_id = category.discourse_category_id except DiscourseCategory.DoesNotExist: category_id, post_url = create_category( client, category_details['category_name'], category_details['parent_name'], category_details['category_colour'], category_details['category_text_colour']) DiscourseCategory.objects.create( category_name=category_details['category_name'], discourse_category_id=category_id) return category_id, post_url
console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter( logging.Formatter('%(asctime)s %(levelname)s %(message)s')) logger.addHandler(console_handler) logger.info('\nMigrate UseResponse to Discourse.') logger.info('CHANGE OWNER.\n') # =================================================================== # connect to Discourse # =================================================================== logger.info('Connecting to Discourse...') discourse = DiscourseClient(config.DISCOURSE_BASE_URL + '/' + config.DISCOURSE_FOLDER, api_username=(config.DISCOURSE_LOGIN), api_key=(config.DISCOURSE_API_KEY)) # =================================================================== # connect to mysql # =================================================================== logger.info('Connecting to UseResponse (mysql)...') try: useresponse_db = MySQLdb.connect( use_unicode=True, charset='utf8', host=(config.USERESPONSE_DATABASE_HOST), port=(config.USERESPONSE_DATABASE_PORT), user=(config.USERESPONSE_DATABASE_LOGIN), passwd=(config.USERESPONSE_DATABASE_PASSWORD),
console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter( logging.Formatter('%(asctime)s %(levelname)s %(message)s')) logger.addHandler(console_handler) logger.info('\nMigrate UseResponse to Discourse.') logger.info('Migrate TOPICS.\n') # =================================================================== # connect to Discourse # =================================================================== logger.info('Connecting to Discourse...') discourse = DiscourseClient(config.DISCOURSE_BASE_URL + '/' + config.DISCOURSE_FOLDER, api_username=(config.DISCOURSE_LOGIN), api_key=(config.DISCOURSE_API_KEY)) # =================================================================== # connect to mysql # =================================================================== logger.info('Connecting to UseResponse (mysql)...') try: useresponse_db = MySQLdb.connect( use_unicode=True, charset='utf8', host=(config.USERESPONSE_DATABASE_HOST), port=(config.USERESPONSE_DATABASE_PORT), user=(config.USERESPONSE_DATABASE_LOGIN), passwd=(config.USERESPONSE_DATABASE_PASSWORD),
#!/usr/bin/env python from pydiscourse import DiscourseClient client = DiscourseClient( "http://localhost:9292", api_key="8302ca56136b04e4b2b82bc03ca4d4346cb5dc3dad6e3881138b9c232d7d4b94", api_username="******", ) res = client.upload_image("/home/sidd/Downloads/profile.png", "avatar", True, userid=1)
#!/usr/bin/env python3 # *-* coding: utf-8 *-* from pydiscourse import DiscourseClient from pydiscourse.exceptions import DiscourseClientError from extract_Xnet_data import extract_all_groups, extract_groups_from_hruid import yaml import time with open("config.yml") as conf_f: conf = yaml.load(conf_f) URL = conf['Discourse_API_URL'] USERNAME = conf['Discourse_API_username'] API_KEY = conf['Discourse_API_key'] client = DiscourseClient(URL, USERNAME, API_KEY) def discourseName(netName): dName = netName if len(dName) < 3: #this name is too short for discourse, let's prepend _ to it dName = '_' * (3 - len(dName)) + dName elif len(dName) > 20: #this name is too long for discourse, let's cut it dName = dName[:20] return dName def getAllDiscourseMembers(): all_discourse_members = {} for member in client.users():
print("Error: No discourse username provided") sys.exit(1) if discourse_api_key is None: print("Error: No discourse api_key provided") sys.exit(1) bot = discord.Client() discord_token = discord_config.get("token", None) if discord_config is None: print("Error: No discord token provided") sys.exit(1) discourse_client = DiscourseClient(discourse_site, api_username=discourse_username, api_key=discourse_api_key) def get_news(bot, client): watch = ["yong", "hal"] latest = "last_posted_at" created = "created_at" # Adjust this according to where your server is located adjust_timezone = 5 * 60 * 60 now = datetime.now().timestamp() update_id, update_slug = 257, "gameshell-updates" date_format = lambda _: datetime.strptime(_, "%Y-%m-%dT%H:%M:%S.%fZ") get_timestamp = lambda _: date_format(_).timestamp() topics = client.latest_topics()["topic_list"]["topics"]
console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter( logging.Formatter('%(asctime)s %(levelname)s %(message)s')) logger.addHandler(console_handler) logger.info('\nMigrate UseResponse to Discourse.') logger.info('Migrate USERS.\n') # =================================================================== # connect to Discourse # =================================================================== logger.info('Connecting to Discourse...') discourse = DiscourseClient(config.DISCOURSE_BASE_URL + '/' + config.DISCOURSE_FOLDER, api_username=(config.DISCOURSE_LOGIN), api_key=(config.DISCOURSE_API_KEY)) # =================================================================== # connect to services # =================================================================== # connect to useresponse database logger.info('Connecting to UseResponse (mysql) %s:%s...' % (config.DRUPAL_DATABASE_HOST, config.DRUPAL_DATABASE_PORT)) try: useresponse_db = MySQLdb.connect( use_unicode=True, charset='utf8', host=(config.USERESPONSE_DATABASE_HOST), port=(config.USERESPONSE_DATABASE_PORT),
def test_login(client: DiscourseClient) -> None: try: client.latest_topics() except DiscourseClientError as e: logging.error(f"Could not perform login: {e}") sys.exit(-1)
class ChildScript(Script): def Setup(self): self.WA_API = WaApiClient() while (not self.WA_API.ConnectAPI(self.config.get('api', 'key'))): time.sleep(5) self.processed_filename = "followup_processed.txt" self.discourse_api = DiscourseClient( self.config.get('discourse_api', 'site'), api_username=self.config.get('discourse_api', 'username'), api_key=self.config.get('discourse_api', 'key')) self.member_levels = [ 'Monthly', '6 months', '12 months', "Scholarship (monthly)", "Scholarship (6 months)", "Scholarship (12 months)" ] self.group_name = 'MakeICT_Members' self.member_group_id = \ self.discourse_api._get("/groups/{0}.json".format(self.group_name))['group']['id'] def SyncUser(self, d_user, wa_contacts): # print(self.discourse_api.user_emails(d_user['user']['username'])) print(d_user['username'], ':', d_user['emails'], ':', [c['Email'] for c in wa_contacts]) is_member = False is_active = False # assert wa_contacts['Email'] in d_user['user']['emails'] for contact in wa_contacts: try: is_member = contact['MembershipLevel'][ 'Name'] in self.member_levels except KeyError: print("No WA membership level found") try: is_active = contact['Status'] == 'Active' and contact[ 'MembershipEnabled'] except KeyError: print("WA contact is not active") # If an active WildApricot account is found, stop looking and sync if is_member and is_active: break if is_member and is_active: print("User is an active member, adding user to group") try: if d_user['primary_group_id'] == self.member_group_id: print("User is already in group") return else: print("User is not in group") except KeyError: print("User has no primary group") try: self.discourse_api.add_group_member(self.member_group_id, d_user['username']) except DiscourseClientError: print("Failed to add user to group") else: print("user is not an active member") if (self.member_group_id == d_user['primary_group_id']): print("removing user from group") self.discourse_api.delete_group_member(self.member_group_id, d_user['id']) else: print("user is not in group") def SyncUsers(self, disc_users, wa_users): for u in disc_users: # if u['user']['username'] != '': # continue u = self.discourse_api.user_all(u['user']['id']) emails = self.discourse_api.user_emails(u['username']) email_list = [emails['email']] email_list += emails['secondary_emails'] u['emails'] = email_list found_contacts = [] for contact in wa_users: if contact['Email'] in u['emails']: print("Found WA user for %s" % contact['Email']) found_contacts.append(contact) self.SyncUser(u, found_contacts) time.sleep(2) def SyncAllUsers(self): response = self.discourse_api._get( '/directory_items.json?period=all&order=post_count') discourse_users = response['directory_items'] while response['meta']['total_rows_directory_items'] > len( discourse_users): response = self.discourse_api._get( response['meta']['load_more_directory_items']) discourse_users += response['directory_items'] print(response['meta']['total_rows_directory_items']) print(len(discourse_users)) wa_contacts = self.WA_API.GetAllContacts() self.SyncUsers(discourse_users, wa_contacts) def SyncNewUsers(self): discourse_users = self.discourse_api.list_users("new") wa_contacts = self.WA_API.GetAllContacts() self.SyncUsers(discourse_users, wa_contacts) def Run(self): self.SyncAllUsers()
console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter( logging.Formatter('%(asctime)s %(levelname)s %(message)s')) logger.addHandler(console_handler) logger.info('\nMigrate UseResponse to Discourse.') logger.info('Migrate COMMENTS.\n') # =================================================================== # connect to Discourse # =================================================================== logger.info('Connecting to Discourse...') discourse = DiscourseClient(config.DISCOURSE_BASE_URL + '/' + config.DISCOURSE_FOLDER, api_username=(config.DISCOURSE_LOGIN), api_key=(config.DISCOURSE_API_KEY)) # =================================================================== # connect to mysql # =================================================================== logger.info('Connecting to UseResponse (mysql)...') try: useresponse_db = MySQLdb.connect( use_unicode=True, charset='utf8', host=(config.USERESPONSE_DATABASE_HOST), port=(config.USERESPONSE_DATABASE_PORT), user=(config.USERESPONSE_DATABASE_LOGIN), passwd=(config.USERESPONSE_DATABASE_PASSWORD),
console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) logger.addHandler(console_handler) logger.info('\nMigrate UseResponse to Discourse.') logger.info('Migrate ATTACHMENTS.\n') # =================================================================== # connect to Discourse # =================================================================== logger.info('Connecting to Discourse...') discourse = DiscourseClient( config.DISCOURSE_BASE_URL + '/' + config.DISCOURSE_FOLDER + '/' + config.DISCOURSE_FOLDER, api_username=(config.DISCOURSE_LOGIN), api_key=(config.DISCOURSE_API_KEY) ) # =================================================================== # connect to mysql # =================================================================== logger.info('Connecting to UseResponse (mysql)...') try: useresponse_db = MySQLdb.connect(use_unicode=True, charset='utf8', host=(config.USERESPONSE_DATABASE_HOST), port=(config.USERESPONSE_DATABASE_PORT), user=(config.USERESPONSE_DATABASE_LOGIN), passwd=(config.USERESPONSE_DATABASE_PASSWORD), db=(config.USERESPONSE_DATABASE_NAME),