Manages websites in the current account: creation, publishing, and branch and app lifecycle. Also covers TLS certificate status, temporary IP whitelists and website level app settings. Reached from GraalJS as the platform's central entry point for website administration tasks that do not belong to a single app. Most methods resolve the current tenant account from the request context, and some are restricted to a website context or to account administrators.

Group: Managers


Properties

PropertyReturnsDescription
centralLoginUrlStringFully qualified URL of the central login page on the root organisation's admin domain, used to sign in once and be recognised across the account's websites.
currentOpCurrentOpThe current operation, a per-request holder of attributes such as the cached CSP script nonce, shared across code handling the current request.
currentResourceCommonResourceThe current page being rendered, if there is a request in context with a "page" attribute or a rendering data model holding one.
currentSiteOnPrimaryDomainbooleanWhether the current request's host name is on the account's primary domain, ie the current root folder is a website and the request host ends with the primary domain. Returns false outside a website context, when there is no current request, or when the account has no primary domain configured.
currentWebsiteWebsiteThe website the current request is being served against, if the current root folder is a website's root folder.
hostnameStringThe local host name of the server process handling the request, as reported by the operating system.
ipWhitelistMaxHoursintThe longest window a whitelist may cover, in hours, for the admin page to enforce in the browser too.
rootFolderRootFolderThe root folder resolved for the current request, eg a website's root folder when the request is served against a website, or the admin root folder in an admin context.
websitesList<Website>Every website belonging to the current account.
websiteSigninProvidersSigninProvidersListThe sign-in providers (eg social/SSO login options) available to the current website.

Methods

emailAddressForWebsite(Website website) · findWebsitesWithApp(String appId) · updateAll(Branch branch, boolean missingOnly) · getMissing(Branch websiteBranch, Narrative narrative) · getUpdates(Branch websiteBranch, boolean missingOnly) · getApps(Branch websiteBranch) · getCentralLoginUrl() · isCurrentSiteOnPrimaryDomain() · getWebsiteSigninProviders() · generateCsrfToken() · generateCsrfToken(Profile currentProfile, String key) · getWebsiteDkimTxtRecord(Website website) · copyContentByHash(String sourceHash, Branch websiteBranch, Object oTransformFn) · findWebsiteById(long id) · findWebsiteByName(String name) · createAndPopulateWebsite(String newName, String websiteTitle, String themeName, String contentHash) · saveWebsite(Website website) · addGroupToWebsite(Group group, Website website) · getCertificatesForWebsite(Website website) · getChainStatus(WebsiteSecureCertificateBean wscb) · getCertificateStatus(WebsiteSecureCertificateBean wscb) · getPrivateKeyStatus(WebsiteSecureCertificateBean wscb) · getCertificateIssuer(WebsiteSecureCertificateBean wscb) · initDefaultApps(Branch websiteBranch, String themeName) · setAppStatuses(Branch websiteBranch, List<String> appIds, boolean enabled) · setAppStatus(Branch websiteBranch, String appId, boolean enabled) · getWebsites() · getIpWhitelists(Website website) · createIpWhitelist(String websiteName, String ips, String cidrs, Date startDate, Date endDate, String reason) · revokeIpWhitelist(long id) · revokeIpWhitelist(WebsiteIpWhitelist whitelist) · getIpWhitelistMaxHours() · findChildWebsites(Long childOrgId) · updateEditable(Website website, Branch branch, boolean isEditable) · publish(Branch branch) · publish(Branch branch, boolean reindex) · isForceHttps(Website website) · getSecuritySettings(Branch branch) · findBestContentDeliveryService() · findContentDeliveryService(Website website) · getRootFolder() · websiteRootFolder(Website website) · websiteRootFolder(Website website, Branch b) · checkStylesheet(Website website, Branch branch) · findThemeParams(Website website, Branch branch) · websiteDomainName(Website website) · websiteDomainName(Website website, Branch branch) · websiteUrl(Website website) · websiteUrl(Website website, Branch branch) · getCurrentWebsite() · getCurrentResource() · findAvailableCdns() · findApp(Website w, String id) · findApp(Website website, Branch b, String id) · updatePageContent(Branch branch, Path path, Map<String,String> properties) · listDirectory(Branch branch, String dirPath) · findAvailableComponents(Branch branch, String pagePath) · findComponentApps(Branch branch, String pagePath) · setSetting(String appId, String name, String value) · setSetting(String appId, String name, Branch websiteBranch, String value) · getSetting(String appId, String name) · getRawSetting(String appId, String name) · getRawSetting(String appId, String name, Branch branch) · getSetting(String appId, String name, Branch websiteBranch) · updateAllWebsiteDeps(Branch branch) · updateAllWebsiteDeps(Branch branch, boolean missingOnly) · updateAllWebsiteDeps(Branch branch, boolean missingOnly, Consumer<String> progress) · findMappingsForApp(Branch branch) · getCurrentOp() · findCspOptions(WebsiteRootFolder webroot) · findXContentTypeOptions(WebsiteRootFolder webroot) · generateScriptNonce() · externalUrl(Website website, String path) · getHostname() · removeWebsiteGroup(Website website, Group group) · getWebsiteGroups(Website website)

emailAddressForWebsite(Website website)

Returns: String

Builds a "noreply@" sender address for the given website, using the website's domain name.

ParameterDescription
websitethe website to build the address for

findWebsitesWithApp(String appId)

Returns: List<Website>

Finds the websites in the current account which have the given app active.

ParameterDescription
appIdthe instance id of the app to search for

updateAll(Branch branch, boolean missingOnly)

Returns: void

Updates every app in the current account to its latest available version, ignoring the given branch and missingOnly arguments and always updating unconditionally at the account level.

ParameterDescription
branchnot used by this overload
missingOnlynot used by this overload

getMissing(Branch websiteBranch, Narrative narrative)

Returns: List<Dependency>

Finds app dependencies that are required by an active app but are not themselves active, for the given website branch or, if no branch is given, at the account level. Progress notes are appended to the given narrative as the check runs.

ParameterDescription
websiteBranchthe website branch to check, or null to check at the account level
narrativecollects progress notes as the check runs, may be null

getUpdates(Branch websiteBranch, boolean missingOnly)

Returns: List<Update>

Finds apps in the given website branch, or at the account level if no branch is given, for which a newer version is available in the marketplace.

ParameterDescription
websiteBranchthe website branch to check, or null to check at the account level
missingOnlyif true, only returns apps that are missing rather than every app with an update available

getApps(Branch websiteBranch)

Returns: List<AppControlBean>

Finds every app available to the given website branch, or to the account if no branch is given, each wrapped with its active status and version information for display on an app management page.

ParameterDescription
websiteBranchthe website branch to list apps for, or null to list at the account level

getCentralLoginUrl()

Returns: String

Fully qualified URL of the central login page on the root organisation's admin domain, used to sign in once and be recognised across the account's websites.

isCurrentSiteOnPrimaryDomain()

Returns: boolean

Whether the current request's host name is on the account's primary domain, ie the current root folder is a website and the request host ends with the primary domain. Returns false outside a website context, when there is no current request, or when the account has no primary domain configured.

getWebsiteSigninProviders()

Returns: SigninProvidersList

The sign-in providers (eg social/SSO login options) available to the current website.

generateCsrfToken()

Returns: String

Generates a CSRF token for the current user, using the first CSRF key configured in the current root folder's IDP policy. Returns an empty string if there is no IDP policy or it defines no CSRF keys.

generateCsrfToken(Profile currentProfile, String key)

Returns: String

Generates a CSRF token for the given profile and key, combining the profile's id and the current time. Returns null if the key is blank or token generation fails.

ParameterDescription
currentProfilethe profile the token is generated for, or null to generate an anonymous token with a user id of 0
keythe CSRF key to sign the token with

getWebsiteDkimTxtRecord(Website website)

Returns: String

Builds the DNS TXT record value that publishes the website's DKIM public key, derived from its stored DKIM private key. Returns null if the website is null or has no DKIM selector configured.

ParameterDescription
websitethe website to build the DKIM record for

copyContentByHash(String sourceHash, Branch websiteBranch, Object oTransformFn)

Returns: void

Copies all resources (files and folders) identified by the source hash into the destination branch. Folders within the source are preserved. An optional transform function may replace or rename each file as it is copied.

ParameterDescription
sourceHashthe hash identifying the source content tree to copy from
websiteBranchthe destination branch to copy resources into
oTransformFnoptional callback, given the name and hash of each existing file, returning either a String or byte array or input stream to use as the new content, or null to keep the existing hash; may be a JavaScript function or a Java Function, or null to copy unchanged

findWebsiteById(long id)

Returns: Website

Finds a website in the current account by its database id.

ParameterDescription
idthe website's id

findWebsiteByName(String name)

Returns: Website

Finds a website in the current account by its name.

ParameterDescription
namethe website's name

createAndPopulateWebsite(String newName, String websiteTitle, String themeName, String contentHash)

Returns: Website

Creates a new website in the current account, installs the default apps for the given theme (unless the theme name is blank), and optionally sets the live branch content to the given hash. Fires a WebsiteCreatedEvent once the website is saved.

ParameterDescription
newNamethe new website's path-safe name, must be unique within the account
websiteTitlethe new website's display title
themeNamethe theme to enable and initialise default apps for, or blank to skip app initialisation
contentHashthe hash of a content tree to set as the live branch's head commit, or null to leave it empty

saveWebsite(Website website)

Returns: void

Saves changes made to a website record, such as its title, domain name or redirect. The website must be one obtained from this manager, so that it is already scoped to the current account.

ParameterDescription
websitethe website to save

addGroupToWebsite(Group group, Website website)

Returns: void

Adds a group to a website, granting the group's members whatever access the website's group configuration gives them.

ParameterDescription
groupthe group to add
websitethe website to add the group to

getCertificatesForWebsite(Website website)

Returns: CommonList<WebsiteSecureCertificateBean>

Finds the secure (TLS) certificates that have been uploaded for a website.

ParameterDescription
websitethe website to find certificates for

getChainStatus(WebsiteSecureCertificateBean wscb)

Returns: String

Validates a certificate's chain (its own certificate followed by any configured root certificates) and reports the outcome as a status string for display: "valid", "invalid" if the chain does not validate or cannot be validated, or "missing" if the chain cannot even be parsed.

ParameterDescription
wscbthe certificate bean to validate the chain for

getCertificateStatus(WebsiteSecureCertificateBean wscb)

Returns: String

Reports the validity status of a certificate against its website's domain and expiry date, as a status string for display: "none" if no certificate text is stored, "expired" if past its expiry date, "valid" or "selfsigned-valid" if it validates for the website's domain, otherwise "notvalid" or "selfsigned-notvalid".

ParameterDescription
wscbthe certificate bean to check

getPrivateKeyStatus(WebsiteSecureCertificateBean wscb)

Returns: String

Reports whether a certificate's stored private key matches its certificate, as a status string for display: "none" if no private key is stored, "no-certificate" if there is a key but no certificate to check it against, otherwise "valid" or "not-valid".

ParameterDescription
wscbthe certificate bean to check

getCertificateIssuer(WebsiteSecureCertificateBean wscb)

Returns: String

Builds a display string for a certificate's issuer, combining the issuer's organisation and common name from its distinguished name, eg "Example CA - Example Root".

ParameterDescription
wscbthe certificate bean to read the issuer from

initDefaultApps(Branch websiteBranch, String themeName)

Returns: void

Enables the given theme and every core app for the website's organisation, plus the KToolbar app, in the given branch. Used to set up a new website's default set of active apps.

ParameterDescription
websiteBranchthe branch to enable the theme and default apps in
themeNamethe theme to enable

setAppStatuses(Branch websiteBranch, List<String> appIds, boolean enabled)

Returns: void

Turns a batch of apps on or off in a website branch.

ParameterDescription
websiteBranchthe branch to change app status in
appIdsthe instance ids of the apps to change
enabledtrue to enable the apps, false to disable them

setAppStatus(Branch websiteBranch, String appId, boolean enabled)

Returns: void

Turns an app on or off in a website branch.

ParameterDescription
websiteBranchthe branch to change app status in
appIdthe instance id of the app to change
enabledtrue to enable the app, false to disable it

getWebsites()

Returns: List<Website>

Every website belonging to the current account.

getIpWhitelists(Website website)

Returns: List<WebsiteIpWhitelist>

One website's temporary IP whitelists, expired ones included, newest first.

ParameterDescription
websitethe website to list for

createIpWhitelist(String websiteName, String ips, String cidrs, Date startDate, Date endDate, String reason)

Returns: WebsiteIpWhitelist

Lets a set of addresses reach one of the account's websites for a fixed window. The global IDP policy decides what an allowed request then gets, see WebsiteIpWhitelistIDPExpression.

ParameterDescription
websiteNamethe name of the website, resolved strictly within the current account
ipssingle IP addresses, one per line, may be blank if cidrs are given
cidrsCIDR ranges, one per line, may be blank if ips are given
startDatewhen the whitelist starts applying
endDatewhen it stops, no more than WebsiteIpWhitelist.MAX_DURATION_HOURS after the start
reasonfree text describing why it was asked for, may be blank

revokeIpWhitelist(long id)

Returns: void

Ends a whitelist immediately, whether or not it has started, looking it up by id.

ParameterDescription
idthe whitelist id

revokeIpWhitelist(WebsiteIpWhitelist whitelist)

Returns: void

Ends a whitelist immediately, whether or not it has started.

ParameterDescription
whitelistthe whitelist to end, which must belong to the current account

getIpWhitelistMaxHours()

Returns: int

The longest window a whitelist may cover, in hours, for the admin page to enforce in the browser too.

findChildWebsites(Long childOrgId)

Returns: Map<Long,String>

Retrieves a map of child account websites and their titles for the current tenant organisation.

ParameterDescription
childOrgIdthe id of the child organisation to retrieve websites for

updateEditable(Website website, Branch branch, boolean isEditable)

Returns: void

Sets whether a website branch may be edited: a non-editable branch is marked readonly, and an editable branch has its cached published data cleared.

ParameterDescription
websitethe website the branch belongs to, used only for logging
branchthe branch to update
isEditabletrue to make the branch editable, false to make it readonly

publish(Branch branch)

Returns: void

Publishes a branch as its repository's live branch, without triggering a search reindex. See publish(Branch, boolean) for the full behaviour.

ParameterDescription
branchthe branch to publish

publish(Branch branch, boolean reindex)

Returns: void

Publishes a branch as its repository's live branch. For a website, first compiles and saves its combined JS, LESS and CSS dependencies. The whole operation runs under a global lock on the repository. If reindex is true, a search reindex job is queued for every search index configured for the repository's account.

ParameterDescription
branchthe branch to publish
reindexif true, queues a search reindex job for each configured index after publishing

isForceHttps(Website website)

Returns: boolean

Whether the website's live branch is configured to force HTTPS.

ParameterDescription
websitethe website to check

getSecuritySettings(Branch branch)

Returns: Map<String,String>

Reads the security settings configured for a website branch: HTTPS enforcement, HSTS, and the security response headers the branch sends. These are branch scoped rather than website scoped, so a draft branch can carry different settings to the live one. A value that has never been set is returned as null, which is not the same as being switched off - a null xContentTypeOptions means the header is not sent at all, where an empty string means it was explicitly disabled.

ParameterDescription
branchthe website branch to read settings for

findBestContentDeliveryService()

Returns: String

Finds the name of the content delivery service used by the first website in the current account that has a CDN configured and is neither an alias nor a redirect.

findContentDeliveryService(Website website)

Returns: ContentDeliveryService

The content delivery service configured for a website.

ParameterDescription
websitethe website to look up

getRootFolder()

Returns: RootFolder

The root folder resolved for the current request, eg a website's root folder when the request is served against a website, or the admin root folder in an admin context.

websiteRootFolder(Website website)

Returns: WebsiteRootFolder

The root folder for a website's live branch.

ParameterDescription
websitethe website to get the root folder for

websiteRootFolder(Website website, Branch b)

Returns: WebsiteRootFolder

The root folder for a website's given branch.

ParameterDescription
websitethe website to get the root folder for
bthe branch to get the root folder for

checkStylesheet(Website website, Branch branch)

Returns: String

Compiles the website version's stylesheet exactly as the site builds it, and reports the first LESS error, or null when it compiles. Every LESS dependency is concatenated into one document before compiling, so a fault in any one of them - a stray brace in a site's own custom stylesheet, a variable that does not exist - fails all of it, and a caller checking only its own file would not see that. <p> Worth calling before leaving a change in place, because the failure is otherwise close to invisible: the error is served with a CSS content type and a 200, cacheable for a week, so the site renders unstyled and nothing says why. <p> The sources are read and compiled directly rather than by fetching the combined .compile.less resource, because that URL only resolves within a request for the site itself - and this is called from an admin or agent context, about a different site.

ParameterDescription
websitethe website to compile
branchthe version of that website

findThemeParams(Website website, Branch branch)

Returns: Map<String,String>

Every LESS parameter in force for one website version, merged in the order the stylesheet resolves them: Bootstrap's own defaults, Kademi's additions, the installed theme's variables, and finally the site's own overrides in /theme/theme-params.less, which win. <p> Given a website rather than read from the current context because the answer genuinely differs per site - the set of parameters depends on which theme is installed - and because resolving them walks the theme overlay for whichever host is current. Without arranging that first, a caller asking about one site is quietly told about another's theme.

ParameterDescription
websitethe website whose parameters are wanted
branchthe version of that website

websiteDomainName(Website website)

Returns: String

The domain name a website's live branch is served on.

ParameterDescription
websitethe website to get the domain name for

websiteDomainName(Website website, Branch branch)

Returns: String

The domain name a website's given branch is served on.

ParameterDescription
websitethe website to get the domain name for
branchthe branch to get the domain name for, optional, if not provided will use the live branch

websiteUrl(Website website)

Returns: String

Builds a fully qualified URL for the live version of the given website, using https if the website forces https and http otherwise.

ParameterDescription
websitethe website to build the URL for

websiteUrl(Website website, Branch branch)

Returns: String

Builds a fully qualified URL for the given branch of the given website, using https if the website forces https and http otherwise.

ParameterDescription
websitethe website to build the URL for
branchthe branch whose domain name is used to build the URL

getCurrentWebsite()

Returns: Website

The website the current request is being served against, if the current root folder is a website's root folder.

getCurrentResource()

Returns: CommonResource

The current page being rendered, if there is a request in context with a "page" attribute or a rendering data model holding one.

findAvailableCdns()

Returns: List<ContentDeliveryService>

Every content delivery service configured on this server instance.

findApp(Website w, String id)

Returns: Application

Finds an active app on a website's live branch by its instance id.

ParameterDescription
wthe website to search
idthe instance id of the app to find

findApp(Website website, Branch b, String id)

Returns: Application

Finds an active app on a website's given branch by its instance id, falling back to the live branch if no branch is given.

ParameterDescription
websitethe website to search
bthe branch to search, or null to search the live branch
idthe instance id of the app to find

updatePageContent(Branch branch, Path path, Map<String,String> properties)

Returns: void

Creates or updates an HTML page resource directly via the VfsSession (DataSession) API, bypassing the Milton resource/controller layer entirely, ie without a RenderFileResource. Intended for callers such as background jobs which need to write page content but have no HTTP request or controller to hand. If a resource already exists at the path its current content is parsed first, so properties not present in the given map are left unchanged. Missing parent directories are created as needed.

ParameterDescription
branchthe branch to update
paththe path of the HTML resource within the branch
propertiesuses the same keys as RenderFileResource.processForm: template, title, body, itemType, category, tags. Only keys present in the map are applied.

listDirectory(Branch branch, String dirPath)

Returns: List<Map<String,Object>>

Lists the immediate children of a directory within a branch's virtual filesystem, for discovery/traversal of pages and other resources. Pass a null or empty path to list the branch root.

ParameterDescription
branchthe branch (version) of the website to list
dirPathpath of the directory to list, relative to the branch root; null or empty for the root

findAvailableComponents(Branch branch, String pagePath)

Returns: List<KEditorComponent>

Finds the KEditor components available to be added to pages within the given branch, optionally filtered to those relevant to a specific page. Aggregates components registered by every app active on the branch; does not include website-local custom components.

ParameterDescription
branchthe branch (version) of the website to find components for
pagePathoptional path, relative to the branch root, of a page to filter relevant components for; null to return the full catalogue

findComponentApps(Branch branch, String pagePath)

Returns: Map<String,String>

Maps each available component id to the title of the app that provides it, for the same components and the same filtering as findAvailableComponents. <p> Kademi has no components except the ones an app contributes, so "there is no such component" and "this site does not have that app" are entirely different answers to a caller, and only the second one is actionable. The aggregation in findAvailableComponents already knows which app each component came from and discards it; this keeps it, so a caller can say which app to install rather than only that something is absent.

ParameterDescription
branchthe branch (version) of the website to find components for
pagePathoptional path, relative to the branch root, of a page to filter relevant components for; null to return the full catalogue

setSetting(String appId, String name, String value)

Returns: void

Creates or updates a named app setting at the account level.

ParameterDescription
appIdthe instance id of the app the setting belongs to
namethe setting's name
valuethe value to store

setSetting(String appId, String name, Branch websiteBranch, String value)

Returns: void

Creates or updates a named app setting in the given website branch.

ParameterDescription
appIdthe instance id of the app the setting belongs to
namethe setting's name
websiteBranchthe branch to store the setting in
valuethe value to store

getSetting(String appId, String name)

Returns: String

Retrieves a named app setting at the account level.

ParameterDescription
appIdthe instance id of the app the setting belongs to
namethe setting's name

getRawSetting(String appId, String name)

Returns: String

Retrieves a named app setting at the account level, without environment variable substitution applied to the stored value.

ParameterDescription
appIdthe instance id of the app the setting belongs to
namethe setting's name

getRawSetting(String appId, String name, Branch branch)

Returns: String

Retrieves a named app setting in the given branch, without environment variable substitution applied to the stored value.

ParameterDescription
appIdthe instance id of the app the setting belongs to
namethe setting's name
branchthe branch to read the setting from

getSetting(String appId, String name, Branch websiteBranch)

Returns: String

Retrieves a named app setting for the given website branch. If the branch level value is blank this also looks up the account level setting, though the value returned is always the branch level lookup.

ParameterDescription
appIdthe instance id of the app the setting belongs to
namethe setting's name
websiteBranchthe branch to read the setting from

updateAllWebsiteDeps(Branch branch)

Returns: void

Installs or updates every dependency of every active app for the given branch, or at the account level if no branch is given.

ParameterDescription
branchthe branch to update dependencies for, or null to update at the account level

updateAllWebsiteDeps(Branch branch, boolean missingOnly)

Returns: void

Installs or updates every dependency of every active app for the given branch, or at the account level if no branch is given.

ParameterDescription
branchthe branch to update dependencies for, or null to update at the account level
missingOnlyif true, only installs missing dependencies rather than updating every dependency

updateAllWebsiteDeps(Branch branch, boolean missingOnly, Consumer<String> progress)

Returns: void

As updateAllWebsiteDeps(Branch, boolean), but reports which app is being updated as it goes. Intended for callers running this as a background task, so they can show the user the app currently being updated instead of an unqualified spinner.

ParameterDescription
branchthe branch to update dependencies for, or null to update at the account level
missingOnlyif true, only installs missing dependencies rather than updating every dependency
progresscalled with a status message as each app is updated, may be null

findMappingsForApp(Branch branch)

Returns: ControllerMappingList

Finds the controller URL mappings registered by every active app in the given branch.

ParameterDescription
branchthe branch to find app controller mappings for

getCurrentOp()

Returns: CurrentOp

The current operation, a per-request holder of attributes such as the cached CSP script nonce, shared across code handling the current request.

findCspOptions(WebsiteRootFolder webroot)

Returns: String

The configured Content-Security-Policy header options for a website root folder's branch.

ParameterDescription
webrootthe website root folder to look up CSP options for

findXContentTypeOptions(WebsiteRootFolder webroot)

Returns: String

The configured X-Content-Type-Options header value for a website root folder's branch.

ParameterDescription
webrootthe website root folder to look up the header value for

generateScriptNonce()

Returns: String

Generates a random base64 nonce for use in a Content-Security-Policy script-src directive, caching it on the current operation so repeated calls within the same request return the same value.

externalUrl(Website website, String path)

Returns: String

Builds a fully qualified URL for an optional path on the given website.

ParameterDescription
websitethe website to build the URL for
paththe path to append, may be null

getHostname()

Returns: String

The local host name of the server process handling the request, as reported by the operating system.

removeWebsiteGroup(Website website, Group group)

Returns: void

Removes a group's membership of a website. Only applies when both the website and the group belong to the current account; otherwise the request is logged and ignored.

ParameterDescription
websitethe website to remove the group from
groupthe group to remove

getWebsiteGroups(Website website)

Returns: List<Group>

Every group that has been added to a website.

ParameterDescription
websitethe website to list groups for
To get full access to the Kademi Hub existing customers can login here, or new customers can register here.