def ParseWhoisContact(path): if path is None: return None raw_contact = yaml.load_path(path) messages = registrations.GetMessagesModule() parsed_contact = messages.WhoisContact(**raw_contact) return parsed_contact
def _ParseDnsSettingsFromFile(path): """Parses dns_settings from a yaml file. Args: path: YAML file path. Returns: Pair (DnsSettings, DnsUpdateMask) or (None, None) if path is None. """ messages = registrations.GetMessagesModule() dns_settings = util.ParseMessageFromYamlFile( path, messages.DnsSettings, 'DNS settings file \'{}\' does not contain valid dns_settings message'. format(path)) if not dns_settings: return None, None update_mask = None if dns_settings.googleDomainsDns is not None: update_mask = DnsUpdateMask(name_servers=True, google_domains_dnssec=True, glue_records=True) elif dns_settings.customDns is not None: update_mask = DnsUpdateMask(name_servers=True, custom_dnssec=True, glue_records=True) else: raise exceptions.Error( 'dnsProvider is not present in DNS settings file \'{}\'.'.format( path)) return dns_settings, update_mask
def test050PLN(self, price_string): messages = registrations.GetMessagesModule(API_VERSION) expected = messages.Money(units=0, nanos=50 * 10**7, currencyCode='PLN') self.assertEqual(util.ParseYearlyPrice(API_VERSION, price_string), expected)
def test050PLN(self): messages = registrations.GetMessagesModule() expected = messages.Money(units=0, nanos=50 * 10**7, currencyCode='PLN') for test_case in ['0.50PLN']: self.assertEqual(util.ParseYearlyPrice(test_case), expected)
def _CustomNameServers(name_servers, ds_records=None): if not ds_records: ds_records = [] messages = registrations.GetMessagesModule() update_mask = DnsUpdateMask(dns_provider=True) dns_settings = messages.DnsSettings( customDns=messages.CustomDns( nameServers=name_servers, dsRecords=ds_records)) return dns_settings, update_mask
def testDifferentNameServersNotEquivalent(self): messages = registrations.GetMessagesModule(API_VERSION) prev_dns_settings = messages.DnsSettings(customDns=messages.CustomDns( nameServers=['ns1.com', 'ns2.com'])) new_dns_settings = messages.DnsSettings(customDns=messages.CustomDns( nameServers=['new.ns1.com', 'new.ns2.com'])) self.assertFalse( dns_util.NameServersEquivalent(prev_dns_settings, new_dns_settings))
def _GoogleDomainsNameServers(enable_dnssec): messages = registrations.GetMessagesModule() update_mask = DnsUpdateMask(dns_provider=True) ds_state = messages.GoogleDomainsDns.DsStateValueValuesEnum.DS_RECORDS_PUBLISHED if not enable_dnssec: ds_state = messages.GoogleDomainsDns.DsStateValueValuesEnum.DS_RECORDS_UNPUBLISHED dns_settings = messages.DnsSettings( googleDomainsDns=messages.GoogleDomainsDns(dsState=ds_state)) return dns_settings, update_mask
def AssertRegistrationOperational(api_version, registration): messages = registrations.GetMessagesModule(api_version) if registration.state not in [ messages.Registration.StateValueValuesEnum.ACTIVE, messages.Registration.StateValueValuesEnum.SUSPENDED ]: raise exceptions.Error( 'The registration resource must be in state ACTIVE or SUSPENDED, ' 'not \'{}\'.'.format(registration.state))
def MergeContacts(api_version, prev_contacts, new_contacts): domains_messages = registrations.GetMessagesModule(api_version) if new_contacts is None: new_contacts = domains_messages.ContactSettings() return domains_messages.ContactSettings( registrantContact=(new_contacts.registrantContact or prev_contacts.registrantContact), adminContact=(new_contacts.adminContact or prev_contacts.adminContact), technicalContact=(new_contacts.technicalContact or prev_contacts.technicalContact))
def testCustomNameServersDifferentOrderEquivalent(self): messages = registrations.GetMessagesModule(API_VERSION) prev_dns_settings = messages.DnsSettings(customDns=messages.CustomDns( nameServers=['ns1.com', 'ns2.com'], dsRecords=[messages.DsRecord(digest='hash')])) new_dns_settings = messages.DnsSettings(customDns=messages.CustomDns( nameServers=['ns2.com', 'ns1.com'])) self.assertTrue( dns_util.NameServersEquivalent(prev_dns_settings, new_dns_settings))
def MergeContacts(prev_contacts, new_contacts): messages = registrations.GetMessagesModule() if new_contacts is None: new_contacts = messages.ContactSettings() return messages.ContactSettings( registrantContact=(new_contacts.registrantContact or prev_contacts.registrantContact), adminContact=(new_contacts.adminContact or prev_contacts.adminContact), technicalContact=(new_contacts.technicalContact or prev_contacts.technicalContact))
def _CustomNameServers(name_servers, ds_records=None): """Validates name servers and returns (dns_settings, update_mask).""" if not ds_records: ds_records = [] normalized_name_servers = list(map(util.NormalizeDomainName, name_servers)) for ns, normalized in zip(name_servers, normalized_name_servers): if not util.ValidateDomainName(normalized): raise exceptions.Error('Invalid name server: \'{}\'.'.format(ns)) messages = registrations.GetMessagesModule() update_mask = DnsUpdateMask(name_servers=True, custom_dnssec=True) dns_settings = messages.DnsSettings(customDns=messages.CustomDns( nameServers=normalized_name_servers, dsRecords=ds_records)) return dns_settings, update_mask
def ParsePublicContactsAck(notices): """Parses Contact Notices. Returns public_contact_ack enum or None.""" messages = registrations.GetMessagesModule() if notices is None: return False for notice in notices: enum = flags.CONTACT_NOTICE_ENUM_MAPPER.GetEnumForChoice(notice) # pylint: disable=line-too-long if enum == messages.ConfigureContactSettingsRequest.ContactNoticesValueListEntryValuesEnum.PUBLIC_CONTACT_DATA_ACKNOWLEDGEMENT: return enum return None
def testDifferentDnsProvidersNotEquivalent(self): messages = registrations.GetMessagesModule(API_VERSION) prev_dns_settings = messages.DnsSettings( googleDomainsDns=messages.GoogleDomainsDns( nameServers=['ns1.com', 'ns2.com'], dsState=messages.GoogleDomainsDns.DsStateValueValuesEnum. DS_RECORDS_PUBLISHED)) new_dns_settings = messages.DnsSettings(customDns=messages.CustomDns( nameServers=['ns1.com', 'ns2.com'])) self.assertFalse( dns_util.NameServersEquivalent(prev_dns_settings, new_dns_settings))
def PromptForContactPrivacy(api_version, choices, current_privacy=None): """Asks a user for Contacts Privacy. Args: api_version: Cloud Domains API version to call. choices: List of privacy choices. current_privacy: Current privacy. Should be nonempty in update calls. Returns: Privacy enum or None if the user cancelled. """ if not choices: raise exceptions.Error('Could not find supported contact privacy.') domains_messages = registrations.GetMessagesModule(api_version) # Sort the choices according to the privacy strength. choices.sort(key=flags.PrivacyChoiceStrength, reverse=True) if current_privacy: if len(choices) == 1: log.status.Print( 'Your current contact privacy is {}. It cannot be changed.'. format(current_privacy)) return None else: update = console_io.PromptContinue( 'Your current contact privacy is {}.'.format(current_privacy), 'Do you want to change it', default=False) if not update: return None current_choice = 0 for ix, privacy in enumerate(choices): if privacy == flags.ContactPrivacyEnumMapper( domains_messages).GetChoiceForEnum(current_privacy): current_choice = ix else: current_choice = 0 # The strongest available privacy if len(choices) == 1: ack = console_io.PromptContinue( 'The only supported contact privacy is {}.'.format(choices[0]), default=True) if not ack: return None return ParseContactPrivacy(api_version, choices[0]) else: index = console_io.PromptChoice(options=choices, default=current_choice, message='Specify contact privacy') return ParseContactPrivacy(api_version, choices[index])
def testGoogleDomainsNameServersEquivalent(self): messages = registrations.GetMessagesModule(API_VERSION) prev_dns_settings = messages.DnsSettings( googleDomainsDns=messages.GoogleDomainsDns( nameServers=['ns1.com', 'ns2.com'], dsState=messages.GoogleDomainsDns.DsStateValueValuesEnum. DS_RECORDS_PUBLISHED)) new_dns_settings = messages.DnsSettings( googleDomainsDns=messages.GoogleDomainsDns( dsState=messages.GoogleDomainsDns.DsStateValueValuesEnum. DS_RECORDS_UNPUBLISHED)) self.assertTrue( dns_util.NameServersEquivalent(prev_dns_settings, new_dns_settings))
def PromptForTransferLockState(api_version, transfer_lock=None): """Prompts the user for new transfer lock state.""" messages = registrations.GetMessagesModule(api_version) if transfer_lock is not None: log.status.Print('Your current Transfer Lock state is: {}'.format( six.text_type(transfer_lock))) options = list(flags.TransferLockEnumMapper(messages).choices) index = console_io.PromptChoice( options=options, cancel_option=True, default=len(options), # Additional 'cancel' option. message='Specify new transfer lock state') if index >= len(options): return None return ParseTransferLockState(api_version, options[index])
def PromptForContacts(api_version, current_contacts=None): """Interactively prompts for Whois Contact information.""" domains_messages = registrations.GetMessagesModule(api_version) create_call = (current_contacts is None) if not console_io.PromptContinue( 'Contact data not provided using the --contact-data-from-file flag.', prompt_string='Do you want to enter it interactively', default=create_call): return None if create_call: contact = _PromptForSingleContact(domains_messages) return domains_messages.ContactSettings(registrantContact=contact, adminContact=contact, technicalContact=contact) choices = [ 'all the contacts to the same value', 'registrant contact', 'admin contact', 'technical contact' ] # TODO(b/166210862): Make it a loop. index = console_io.PromptChoice( options=choices, cancel_option=True, default=0, message='Which contact do you want to change?') if index == 0: contact = _PromptForSingleContact(domains_messages, current_contacts.registrantContact) return domains_messages.ContactSettings(registrantContact=contact, adminContact=contact, technicalContact=contact) if index == 1: contact = _PromptForSingleContact(domains_messages, current_contacts.registrantContact) return domains_messages.ContactSettings(registrantContact=contact) if index == 2: contact = _PromptForSingleContact(domains_messages, current_contacts.adminContact) return domains_messages.ContactSettings(adminContact=contact) if index == 3: contact = _PromptForSingleContact(domains_messages, current_contacts.technicalContact) return domains_messages.ContactSettings(technicalContact=contact) return None
def ParseYearlyPrice(price_string): """Parses money string as type Money.""" if not price_string: return None try: units, cents, currency = _ParseMoney(price_string) except ValueError: raise exceptions.Error( 'Yearly price \'{}\' is not valid.'.format(price_string)) if currency == '$': currency = 'USD' messages = registrations.GetMessagesModule() return messages.Money(units=int(units), nanos=cents * 10**7, currencyCode=currency)
def Run(self, args): """Run the search domains command.""" client = registrations.RegistrationsClient() location_ref = args.CONCEPTS.location.Parse() # Sending the query direcyly to server (without normalization). suggestions = client.SearchDomains(location_ref, args.domain_query) for s in suggestions: try: s.domainName = util.PunycodeToUnicode(s.domainName) except UnicodeError: pass # Do not change the domain name. if not suggestions: messages = registrations.GetMessagesModule() suggestions.append(messages.RegisterParameters()) return suggestions
def ParseYearlyPrice(api_version, price_string): """Parses money string as type Money.""" if not price_string: return None try: units, cents, currency = _ParseMoney(price_string) except ValueError: raise exceptions.Error( ('Yearly price \'{}\' is invalid. Please specify the amount followed ' 'by the currency code.').format(price_string)) if currency == '$': currency = 'USD' messages = registrations.GetMessagesModule(api_version) return messages.Money( units=int(units), nanos=cents * 10**7, currencyCode=currency)
def _PromptForSingleContact(unused_current_contact=None): """Asks a user for a single contact data.""" messages = registrations.GetMessagesModule() contact = messages.Contact() contact.postalAddress = messages.PostalAddress() # TODO(b/166210862): Use defaults from current_contact. # But then: How to clear a value? # TODO(b/166210862): Better validation: Call validate_only after each prompt. contact.postalAddress.recipients.append( util.PromptWithValidator(validator=util.ValidateNonEmpty, error_message=' Name must not be empty.', prompt_string='Full name: ')) contact.postalAddress.organization = console_io.PromptResponse( 'Organization (if applicable): ') contact.email = util.PromptWithValidator( validator=util.ValidateEmail, error_message=' Invalid email address.', prompt_string='Email', default=properties.VALUES.core.account.Get()) contact.phoneNumber = util.PromptWithValidator( validator=util.ValidateNonEmpty, error_message=' Phone number must not be empty.', prompt_string='Phone number: ', message='Enter phone number with country code, e.g. "+1.8005550123".') contact.faxNumber = util.Prompt( prompt_string='Fax number (if applicable): ', message='Enter fax number with country code, e.g. "+1.8005550123".') contact.postalAddress.regionCode = util.PromptWithValidator( validator=util.ValidateRegionCode, error_message= (' Country code must be in ISO 3166-1 format, e.g. "US" or "PL".\n' ' See https://support.google.com/business/answer/6270107 for a list ' 'of valid choices.'), prompt_string='Country code: ', message='Enter two-letter country code, e.g. "US" or "PL".') contact.postalAddress.postalCode = console_io.PromptResponse( 'Postal code/zipcode: ') contact.postalAddress.administrativeArea = console_io.PromptResponse( 'State (if applicable): ') contact.postalAddress.locality = console_io.PromptResponse('City: ') contact.postalAddress.addressLines.append( console_io.PromptResponse('Street address (incl. building, apt): ')) return contact
def _ParseDnsSettingsFromFile(path): """Parses dns_settings from a yaml file. Args: path: YAML file path. Returns: Pair (DnsSettings, DnsUpdateMask) or (None, None) if path is None. """ messages = registrations.GetMessagesModule() dns_settings = util.ParseMessageFromYamlFile( path, messages.DnsSettings, 'DNS settings file \'{}\' does not contain valid dns_settings message'. format(path)) if not dns_settings: return None, None return dns_settings, DnsUpdateMask(dns_provider=True, glue_records=True)
def _DisableDnssec(dns_settings): """Returns DNS settings (and update mask) with DNSSEC disabled.""" if dns_settings is None: return None, None messages = registrations.GetMessagesModule() if dns_settings.googleDomainsDns is not None: updated_dns_settings = messages.DnsSettings( googleDomainsDns=messages.GoogleDomainsDns( dsState=messages.GoogleDomainsDns.DsStateValueValuesEnum. DS_RECORDS_UNPUBLISHED)) update_mask = DnsUpdateMask(google_domains_dnssec=True) elif dns_settings.customDns is not None: updated_dns_settings = messages.DnsSettings( customDns=messages.CustomDns(dsRecords=[])) update_mask = DnsUpdateMask(custom_dnssec=True) else: return None, None return updated_dns_settings, update_mask
def ParseDNSSettings(api_version, name_servers, cloud_dns_zone, use_google_domains_dns, dns_settings_from_file, domain, enable_dnssec=True, dns_settings=None): """Parses DNS settings from a flag. At most one of the arguments (except domain) should be non-empty. Args: api_version: Cloud Domains API version to call. name_servers: List of name servers cloud_dns_zone: Cloud DNS Zone name use_google_domains_dns: Information that Google Domains name servers should be used. dns_settings_from_file: Path to a yaml file with dns_settings. domain: Domain name corresponding to the DNS settings. enable_dnssec: Enable DNSSEC for Google Domains name servers or Cloud DNS Zone. dns_settings: Current DNS settings. Used during Configure DNS only. Returns: A pair: (messages.DnsSettings, DnsUpdateMask) to be updated, or (None, None) if all the arguments are empty. """ domains_messages = registrations.GetMessagesModule(api_version) if name_servers is not None: return _CustomNameServers(domains_messages, name_servers) if cloud_dns_zone is not None: nameservers, ds_records = _GetCloudDnsDetails(domains_messages, cloud_dns_zone, domain, enable_dnssec) return _CustomNameServers(domains_messages, nameservers, ds_records) if use_google_domains_dns: return _GoogleDomainsNameServers(domains_messages, enable_dnssec) if dns_settings_from_file is not None: return _ParseDnsSettingsFromFile(domains_messages, dns_settings_from_file) if dns_settings is not None and not enable_dnssec: return _DisableDnssec(domains_messages, dns_settings) return None, None
def PromptForWhoisContact(): """Interactively prompts for Whois Contact information.""" if not console_io.PromptContinue( 'Registrant contact information not provided', prompt_string='Do you want to enter it interactively', default=False): return None messages = registrations.GetMessagesModule() whois_contact = messages.WhoisContact() whois_contact.postalAddress = messages.PostalAddress() # TODO(b/110077203): Improve interactive address info. whois_contact.postalAddress.recipients.append( console_io.PromptWithValidator(validator=_ValidateNonEmpty, error_message='Name must not be empty.', prompt_string=' full name: ')) whois_contact.postalAddress.organization = console_io.PromptResponse( ' organization (if applicable): ') whois_contact.email = console_io.PromptWithDefault( message=' email', default=properties.VALUES.core.account.Get()) whois_contact.phoneNumber = console_io.PromptWithValidator( validator=_ValidateNonEmpty, error_message='Phone number must not be empty.', prompt_string=' phone number: ', message='Enter phone number with country code, e.g. "+1.1234567890".') whois_contact.postalAddress.regionCode = console_io.PromptWithValidator( validator=_ValidateRegionCode, error_message=( 'Country code must be in ISO 3166-1 format, e.g. "US" or "PL".\n' 'See https://support.google.com/business/answer/6270107 for a list ' 'of valid choices.'), prompt_string=' country code: ', message='Enter two-letter country code, e.g. "US" or "PL".') whois_contact.postalAddress.postalCode = console_io.PromptResponse( ' postal code/zipcode: ') whois_contact.postalAddress.administrativeArea = console_io.PromptResponse( ' state (if applicable): ') whois_contact.postalAddress.locality = console_io.PromptResponse( ' city: ') whois_contact.postalAddress.addressLines.append( console_io.PromptResponse(' street address (incl. building, apt): ')) return whois_contact
def ParseContactData(path): """Parses contact data from a yaml file.""" messages = registrations.GetMessagesModule() class ContactData(_messages.Message): """Message that should be present in YAML file with contacts data.""" # pylint: disable=invalid-name allContacts = _messages.MessageField(messages.Contact, 1) registrantContact = _messages.MessageField(messages.Contact, 2) adminContact = _messages.MessageField(messages.Contact, 3) technicalContact = _messages.MessageField(messages.Contact, 4) contacts = util.ParseMessageFromYamlFile( path, ContactData, 'Contact data file \'{}\' does not contain valid contact messages'. format(path)) if not contacts: return None parsed_contact = None if contacts.allContacts: for field in ['registrantContact', 'adminContact', 'technicalContact']: if contacts.get_assigned_value(field): raise exceptions.Error( ('Contact data file \'{}\' cannot contain both ' 'allContacts and {} fields.').format(path, field)) parsed_contact = messages.ContactSettings( registrantContact=contacts.allContacts, adminContact=contacts.allContacts, technicalContact=contacts.allContacts) else: parsed_contact = messages.ContactSettings( registrantContact=contacts.registrantContact, adminContact=contacts.adminContact, technicalContact=contacts.technicalContact) return parsed_contact
def _ConvertDnsKeys(dns_messages, dns_keys): """Converts DnsKeys to DsRecords.""" messages = registrations.GetMessagesModule() ds_records = [] for key in dns_keys: if key.type != dns_messages.DnsKey.TypeValueValuesEnum.keySigning: continue if not key.isActive: continue try: algorithm = messages.DsRecord.AlgorithmValueValuesEnum( six.text_type(key.algorithm).upper()) for d in key.digests: digest_type = messages.DsRecord.DigestTypeValueValuesEnum( six.text_type(d.type).upper()) ds_records.append( messages.DsRecord(keyTag=key.keyTag, digest=d.digest, algorithm=algorithm, digestType=digest_type)) except TypeError: continue # Ignore unsupported algorithms and digest types. return ds_records
def test12USD(self, price_string): messages = registrations.GetMessagesModule(API_VERSION) expected = messages.Money(units=12, nanos=0, currencyCode='USD') self.assertEqual(util.ParseYearlyPrice(API_VERSION, price_string), expected)
def ParseTransferLockState(api_version, transfer_lock_state): messages = registrations.GetMessagesModule(api_version) if transfer_lock_state is None: return None return flags.TransferLockEnumMapper(messages).GetEnumForChoice( transfer_lock_state)