<?php
declare(strict_types=1);
namespace Harmonizely\Model;
use DateTimeImmutable;
use DateTimeZone;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Exception;
use FOS\UserBundle\Model\User as BaseUser;
use Harmonizely\Core\DTO\SecondFactorCredentialsDTO;
use Harmonizely\Core\StringUtil;
use Harmonizely\DTO\SuperAdmin\Customer\Response\CustomerDetailedDTO;
use Harmonizely\DTO\User\Response\UserDTO;
use Harmonizely\Entity\ApiKeyEntity;
use Harmonizely\Entity\Contract\INamedObjectEntity;
use Harmonizely\Entity\MigrationSubscriptionEntity;
use Harmonizely\Entity\OrganizationTagEntity;
use Harmonizely\Entity\ReviewEntity;
use Harmonizely\Entity\RoutingFormEntity;
use Harmonizely\Entity\UserCancellationPolicyEntity;
use Harmonizely\Entity\UserEmailLogEntity;
use Harmonizely\Entity\UserEmailUnsubscribeEntity;
use Harmonizely\Entity\UserGoogleAuthenticatorEntity;
use Harmonizely\Entity\UserLimitEntity;
use Harmonizely\Entity\UserLoginCodeEntity;
use Harmonizely\Entity\UserOAuthEntity;
use Harmonizely\Entity\UserPushNotificationLogEntity;
use Harmonizely\Entity\UserRelationEntity;
use Harmonizely\Entity\UserSmsLogEntity;
use Harmonizely\Entity\UserSsoEntity;
use Harmonizely\Entity\UserWidgetEntity;
use Harmonizely\Entity\ZapierEntity;
use Harmonizely\Service\Subscription\Voter\SubscriptionVoter;
use Harmonizely\Types\CalendarLayoutType;
use Harmonizely\Types\UserSsoLoginType;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberFormat;
use libphonenumber\PhoneNumberUtil;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Validator\Constraints as Assert;
use Harmonizely\Entity\UserSocialLinkEntity;
use Harmonizely\Entity\UserTaxEntity;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface as BaseUserInterface;
use Harmonizely\Types\DateFormatType;
use Harmonizely\Entity\PollEntity;
use Harmonizely\DTO\User\Response\SimpleUserDTO;
class User extends BaseUser implements EquatableInterface, UserInterface, INamedObjectEntity, BannerInterface
{
use RtlTrait;
use BannerTrait;
use AdaTrait;
use TimestampableTrait;
use UuidTrait {
__construct as private initUuid;
}
/**
* @var mixed
*/
protected $id;
/**
* @var string
*/
protected $firstName;
/**
* @var string
*/
protected $lastName;
/**
* @var string
*/
protected $fullName = '';
/**
* @var CalendarAccountInterface
*/
protected $calendarAccount;
/**
* @var CalendarAccountInterface[]|Collection
*/
protected $calendarAccounts;
/**
* @Assert\NotBlank
*
* @var string
*/
protected $slug;
/**
* @var string|null
*/
protected $intro;
/**
* @var string
*/
protected $timezone;
/**
* @var string
*/
protected $locale;
/**
* @var File
*/
protected $avatarFile;
/**
* @var string
*/
protected $avatarName;
/**
* @var int
*/
protected $avatarSize;
/**
* @var int|null
*/
protected $companyLogoFile;
/**
* @var int|null
*/
protected $companyLogoName;
/**
* @var int|null
*/
protected $companyLogoSize;
/**
* @var SubscriptionInterface
*/
protected $subscription;
/**
* @var Collection
*/
protected $integrations;
/**
* @var bool
*/
protected $brandingEnabled = true;
/**
* @var bool
*/
protected $isProxyEnabled = false;
/**
* @var SchedulingPageAppearance
*/
protected $schedulingPageAppearance;
/**
* @var string
*/
private $domain;
/**
* @var Collection|Member[]
*/
private $members;
/**
* @var Collection|Event[]
*/
private $events;
/**
* @var Collection|UserSmsLogEntity[]
*/
private $userSmsLog;
/**
* @var Collection|UserEmailLogEntity[]
*/
private $userEmailLog;
/**
* @var Collection|UserPushNotificationLogEntity[]
*/
private $userPushNotificationLog;
/**
* @var Collection|UserLimitEntity[]
*/
private $userLimit;
/**
* @var Collection|UserTaxEntity[]
*/
private $tax;
/**
* @var Collection|PollEntity[]
*/
private $polls;
/**
* @var Collection|RoutingFormEntity[]
* */
private $routingForms;
/**
* @var Collection|ZapierEntity[]
*/
private $zapiers;
/**
* @var Collection|ApiKeyEntity[]
*/
private $apiKeys;
/**
* @var Collection|UserLoginCodeEntity[]
*/
private $userLoginCode;
/**
* @var array|ArrayCollection
*/
protected $socialLinks = [];
/**
* @var string|null
*/
private $sender;
/**
* @var ApiKey
*/
protected $apiKey;
protected ?string $timeFormat = UserInterface::TWELVE_HOURS_TIME_FORMAT;
protected ?string $dateFormat = DateFormatType::TYPE_DD_MM_YYYY;
protected ?string $clientTimeFormat = UserInterface::AUTO_TIME_FORMAT;
private ?int $dayliteId;
private ?UserPreferences $preferences;
private ?PhoneNumber $phoneNumber;
protected ?int $consent = UserInterface::CONSENT_ACCEPTED;
/**
* @var string|null
*/
private ?string $referral;
/**
* @var string
*/
private string $calendarLayout = CalendarLayoutType::TYPE_WEEKLY;
/**
* @var bool
*/
protected bool $hideUnavailableDates = false;
/**
* @var bool
*/
protected bool $sundayIsFirstDay = false;
/**
* @var bool
*/
protected bool $requireSetPassword = false;
/**
* @var bool
*/
protected bool $requireConfirmEmail = false;
/**
* @var UserGoogleAuthenticatorEntity|null
*/
private ?UserGoogleAuthenticatorEntity $googleAuthenticator = null;
/**
* @var UserSocialLinkEntity|null $socialLink
*/
private ?UserSocialLinkEntity $socialLink = null;
/**
* @var UserSsoEntity|null
*/
private ?UserSsoEntity $userSso = null;
private ?UserCancellationPolicyEntity $userCancellationPolicy = null;
private ?UserWidgetEntity $userWidget = null;
/**
* @var Collection|null
*/
private ?Collection $userToken = null;
/**
* @var Collection|null
*/
private ?Collection $userDeviceToken = null;
/**
* @var Collection|null
*/
private ?Collection $userApiStatistic = null;
/**
* @var Collection|null
*/
private ?Collection $userExport = null;
/**
* @var Collection|UserOAuthEntity[]
*/
private Collection $userOAuth;
/**
* @var Collection
*/
protected Collection $userNews;
/**
* @var Collection
*/
protected Collection $organizationTags;
/**
* @var Collection
*/
protected Collection $userCategories;
/**
* @var MigrationSubscriptionEntity|null
*/
protected ?MigrationSubscriptionEntity $migrationSubscription;
/**
* @var UserEmailUnsubscribeEntity |null
*/
protected ?UserEmailUnsubscribeEntity $userEmailUnsubscribe;
/**
* @var ReviewEntity|null
*/
protected ?ReviewEntity $review;
/**
* @var string|null
*/
protected ?string $address = '';
/**
* @var string|null
*/
protected ?string $state = '';
/**
* @var string|null
*/
protected ?string $city = '';
/**
* @var string|null
*/
protected ?string $zip = '';
/**
* @var string|null
*/
protected ?string $countryId = '';
/**
* @var float|null
*/
protected ?float $lat = null;
/**
* @var float|null
*/
protected ?float $lng = null;
/**
* @var int|null
*/
protected ?int $verificationCode = null;
/**
* @var string|null
*/
protected ?string $otherCategory = '';
/**
* @var bool
*/
protected ?bool $showAddressInEmail = true;
/**
* @var string|null
*/
protected ?string $lastTwoFactorCode = '';
/**
* @var bool
*/
private bool $ssoLoginAllowed;
/**
* User subscriptions
*
* @var Collection
*/
protected Collection $subscriptions;
/**
* @var Collection
*/
protected Collection $userEventTypeTag;
/**
* @var Collection|UserRelationEntity[]
*/
protected Collection $relatedUsers;
/**
* @var string|null
*/
private ?string $welcomeTourStep;
/**
* @var bool
*/
private bool $secondFactorSkipped = false;
/**
* @var bool
*/
private bool $tutorialSkipped = false;
/**
* User constructor.
*/
public function __construct()
{
$this->setCreatedAt(new DateTime());
$this->integrations = new ArrayCollection();
$this->members = new ArrayCollection();
$this->calendarAccounts = new ArrayCollection();
$this->organizationTags = new ArrayCollection();
$this->userCategories = new ArrayCollection();
$this->userOAuth = new ArrayCollection();
$this->userNews = new ArrayCollection();
$this->subscriptions = new ArrayCollection();
$this->socialLink = new UserSocialLinkEntity();
$this->relatedUsers = new ArrayCollection();
$this->initUuid();
$this->generateVerificationCode();
parent::__construct();
}
/**
* {@inheritdoc}
*/
public function setLastLogin(\DateTime $time = null)
{
if (!$this->lastLogin || $time->diff($this->lastLogin)->days > 0) {
if (mt_rand(1, 10) == 1) {
$this->lastLogin = $time;
}
}
return $this;
}
public function getDirectoryCompanyLogin(): string
{
return 'simplymeet_' . $this->getId();
}
/**
* @return void
*/
public function useVerificationCode(): void
{
$this->verificationCode = null;
}
public function generateVerificationCode(): void
{
$this->verificationCode = StringUtil::getSecretCode();
}
/**
* @return int|null
*/
public function getVerificationCode(): ?int
{
return $this->verificationCode;
}
public function setEmail($email)
{
$email = $email ?? '';
parent::setEmail($email);
$this->setUsername($email);
}
/**
* {@inheritdoc}
*/
public function getFirstName(): string
{
$parts = explode(' ', $this->fullName);
return array_shift($parts);
}
/**
* {@inheritdoc}
*/
public function setFirstName(string $firstName)
{
$this->firstName = $firstName;
}
/**
* {@inheritdoc}
*/
public function getLastName(): string
{
return $this->lastName;
}
/**
* {@inheritdoc}
*/
public function setLastName(string $lastName)
{
$this->lastName = $lastName;
}
/**
* @return CalendarAccountInterface[]|Collection
*/
public function getCalendarAccounts(): Collection
{
return $this->calendarAccounts;
}
/**
* @param int $id
* @return CalendarAccountInterface|null
*/
public function getCalendarAccountById(int $id): ?CalendarAccountInterface
{
$calendarAccount = $this->calendarAccounts->filter(function (CalendarAccountInterface $calendarAccount) use ($id) {
return $calendarAccount->getId() === $id;
})->first();
return $calendarAccount ?: null;
}
/**
* @return CalendarAccountInterface[]|Collection
*/
public function getWritableCalendarAccounts(): Collection
{
return $this->calendarAccounts->filter(function (CalendarAccountInterface $calendarAccount) {
return $calendarAccount->isWritable();
});
}
public function setCalendarAccounts(Collection $calendarAccounts): void
{
$this->calendarAccounts = $calendarAccounts;
}
public function addCalendarAccount(CalendarAccountInterface $calendarAccount): void
{
if (!$this->hasCalendarAccount($calendarAccount)) {
$this->calendarAccounts->add($calendarAccount);
$calendarAccount->setUser($this);
}
}
public function removeCalendarAccount(CalendarAccountInterface $calendarAccount): void
{
if ($this->hasCalendarAccount($calendarAccount)) {
$this->calendarAccounts->removeElement($calendarAccount);
$calendarAccount->setUser(null);
}
}
public function hasCalendarAccount(CalendarAccountInterface $calendarAccount): bool
{
return $this->calendarAccounts->contains($calendarAccount);
}
public function hasCalendarConnected(string $type): bool
{
foreach ($this->calendarAccounts as $calendarAccount) {
$calendarService = $calendarAccount->getCalendarService();
if ($calendarService->getType() === $type) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function getSlug(): ?string
{
return $this->slug;
}
/**
* {@inheritdoc}
*/
public function setSlug(?string $slug): void
{
$this->slug = $slug;
}
/**
* {@inheritdoc}
*/
public function getFullName(): string
{
return $this->fullName;
}
/**
* {@inheritdoc}
*/
public function setFullName(string $fullName): void
{
$this->fullName = $fullName;
}
/**
* {@inheritdoc}
*/
public function getIntro(): ?string
{
return $this->intro;
}
/**
* {@inheritdoc}
*/
public function setIntro(?string $intro): void
{
$this->intro = $intro;
}
/**
* {@inheritdoc}
*/
public function getTimezone(): ?string
{
return $this->timezone;
}
/**
* {@inheritdoc}
*/
public function setTimezone(?string $timezone): void
{
$this->timezone = $timezone;
}
/**
* {@inheritdoc}
*/
public function getLocale(): ?string
{
return $this->locale;
}
/**
* {@inheritdoc}
*/
public function setLocale(?string $locale): void
{
$this->locale = $locale;
}
/**
* @return bool
*/
public function isAutoLocale(): bool
{
return $this->getLocale() === 'auto';
}
/**
* @return File
*/
public function getAvatarFile(): ?File
{
return $this->avatarFile;
}
/**
* @param File $avatarFile
*
* @throws Exception
*/
public function setAvatarFile(?File $avatarFile): void
{
$this->avatarFile = $avatarFile;
if (null !== $avatarFile) {
$this->updatedAt = new DateTimeImmutable();
}
}
/**
* @return string
*/
public function getAvatarName(): ?string
{
return $this->avatarName;
}
/**
* @param string $avatarName
*/
public function setAvatarName(?string $avatarName): void
{
$this->avatarName = $avatarName;
}
/**
* @return int
*/
public function getAvatarSize(): ?int
{
return $this->avatarSize;
}
/**
* @param int $avatarSize
*/
public function setAvatarSize(?int $avatarSize): void
{
$this->avatarSize = $avatarSize;
}
public function getSubscription(): ?SubscriptionInterface
{
return $this->subscription;
}
public function setSubscription(?SubscriptionInterface $subscription): void
{
$this->subscription = $subscription;
}
public function getIntegrations(): Collection
{
return $this->integrations;
}
public function setIntegrations(Collection $integrations): void
{
$this->integrations = $integrations;
}
/**
* @param string $type
* @return false|IntegrationInterface
*/
public function getIntegrationByType(string $type)
{
$criteria = Criteria::create()->where(Criteria::expr()->eq('type', $type));
return $this->integrations->matching($criteria)->first();
}
public function addIntegration(IntegrationInterface $integration): void
{
if (!$this->hasIntegration($integration)) {
$this->integrations->add($integration);
$integration->setUser($this);
}
}
public function removeIntegration(IntegrationInterface $integration): void
{
if ($this->hasIntegration($integration)) {
$this->integrations->removeElement($integration);
$integration->setUser(null);
}
}
public function hasIntegration(IntegrationInterface $integration): bool
{
return $this->integrations->contains($integration);
}
public function isBrandingEnabled(): bool
{
if (!SubscriptionVoter::staticVoteOnAttribute(SubscriptionVoter::WHITE_LABEL, $this)) {
return true;
}
return $this->brandingEnabled;
}
public function isCustomCssAvailable(): bool
{
return SubscriptionVoter::staticVoteOnAttribute(SubscriptionVoter::WHITE_LABEL, $this);
}
public function setBrandingEnabled(bool $brandingEnabled): void
{
$this->brandingEnabled = $brandingEnabled;
}
public function isProxyEnabled(): bool
{
return $this->isProxyEnabled;
}
public function setIsProxyEnabled(bool $isProxyEnabled): void
{
$this->isProxyEnabled = $isProxyEnabled;
}
public function getDefaultOrganization(): ?Organization
{
if ($this->members->count() > 0) {
return $this->members->first()->getOrganization();
}
return null;
}
public function getSchedulingPageAppearance(): SchedulingPageAppearance
{
if (false === $this->schedulingPageAppearance instanceof SchedulingPageAppearance) {
$this->schedulingPageAppearance = new UserSchedulingPageAppearance();
$this->schedulingPageAppearance->setUser($this);
}
if (!$this->schedulingPageAppearance->getConfig()) {
$this->schedulingPageAppearance->setConfig(SchedulingPageAppearance::DEFAULT_CONFIG);
}
return $this->schedulingPageAppearance;
}
public function setSchedulingPageAppearance(?SchedulingPageAppearance $schedulingPageAppearance): void
{
$this->schedulingPageAppearance = $schedulingPageAppearance;
}
public function getDomain(): ?string
{
return $this->domain;
}
public function getUserOrOrganizationDomain(): ?string
{
$domain = null;
if ($this->domain) {
$domain = $this->domain;
} else {
$organization = $this->getDefaultOrganization();
if ($organization && $organization->getDomain()) {
$domain = $organization->getDomain();
}
}
return $domain;
}
public function setDomain(?string $domain): void
{
$this->domain = $domain;
}
public function getMembers(): Collection
{
return $this->members;
}
public function setMembers(Collection $members): void
{
$this->members = $members;
}
public function belongsToOrganization(Organization $organization)
{
$members = $organization->getMembers();
$user = $members->filter(function (Member $member) {
return $member->getUser()->getId() === $this->getId();
});
return false === $user->isEmpty();
}
public function getSender(): ?string
{
return $this->sender;
}
public function setSender(?string $sender): void
{
$this->sender = $sender;
}
public function getCompanyLogoFile(): ?File
{
return $this->companyLogoFile;
}
public function setCompanyLogoFile(?File $companyLogoFile): void
{
$this->companyLogoFile = $companyLogoFile;
if (null !== $companyLogoFile) {
$this->updatedAt = new DateTimeImmutable();
}
}
public function getCompanyLogoName(): ?string
{
return $this->companyLogoName;
}
public function setCompanyLogoName(?string $companyLogoName): void
{
$this->companyLogoName = $companyLogoName;
}
public function getCompanyLogoSize(): ?int
{
return $this->companyLogoSize;
}
public function setCompanyLogoSize(?int $companyLogoSize): void
{
$this->companyLogoSize = $companyLogoSize;
}
public function getTimeFormat(): ?string
{
return $this->timeFormat;
}
public function setTimeFormat(?string $timeFormat): void
{
$this->timeFormat = $timeFormat;
}
public function getDateFormat(): ?string
{
return $this->dateFormat;
}
public function setDateFormat(?string $dateFormat): void
{
$this->dateFormat = $dateFormat;
}
/**
* @deprecated
* @return string|null
*/
public function getClientTimeFormat(): ?string
{
return $this->clientTimeFormat;
}
/**
* @deprecated
* @param string|null $clientTimeFormat
* @return void
*/
public function setClientTimeFormat(?string $clientTimeFormat): void
{
$this->clientTimeFormat = $clientTimeFormat;
}
public function getDayliteId(): ?int
{
return $this->dayliteId;
}
public function setDayliteId(?int $dayliteId): void
{
$this->dayliteId = $dayliteId;
}
public function getPreferences(): UserPreferences
{
if (false === $this->preferences instanceof UserPreferences) {
$this->preferences = new UserPreferences();
$this->preferences->setUser($this);
}
return $this->preferences;
}
public function setPreferences(?UserPreferences $preferences): void
{
$this->preferences = $preferences;
}
public function getPhoneNumber(): ?PhoneNumber
{
return $this->phoneNumber;
}
public function getInternationalPhoneNumber(): string
{
if (!$this->phoneNumber instanceof PhoneNumber) {
return '';
}
$phoneUtil = PhoneNumberUtil::getInstance();
return $phoneUtil->format($this->phoneNumber, PhoneNumberFormat::E164);
}
public function setPhoneNumber(?PhoneNumber $phoneNumber): void
{
$this->phoneNumber = $phoneNumber;
}
public function getHelpScoutSignature(): string
{
return hash_hmac(
'sha256',
$this->emailCanonical,
'yHXRcpT4sgbtldHeLccCrlUBl1k5yPTKc8xiojCcQRU='
);
}
public function getConsent(): ?int
{
return $this->consent;
}
public function setConsent(?int $consent): void
{
$this->consent = $consent;
}
/**
* @param string|null $referral
*/
public function setReferral(?string $referral): void
{
$this->referral = $referral;
}
/**
* @return string|null
*/
public function getReferral(): ?string
{
return $this->referral;
}
/**
* Return 2fa authentication type
*
* @return string|null
*/
public function getSecondAuthenticationType(): ?string
{
$types = $this->getAllowedSecondAuthenticationTypes();
$type = reset($types);
if ($type) {
return $type;
}
return null;
}
/**
* Return allowed 2fa types
*
* @return array
*/
public function getAllowedSecondAuthenticationTypes(): array
{
$result = [];
if ($this->googleAuthenticator) {
$result[] = SecondFactorCredentialsDTO::TYPE_GA;
}
return $result;
}
/**
* Return Google Authenticator secret code
*
* @return string|null
*/
public function getGASecretCode(): ?string
{
if ($this->googleAuthenticator) {
return $this->googleAuthenticator->getSecret();
}
return null;
}
/**
* Return Google Authenticator secret code
*
* @param string $secret
* @return void
*/
public function setGASecretCode(string $secret): void
{
if ($this->googleAuthenticator) {
$this->googleAuthenticator->changeSecret($secret);
} else {
$this->googleAuthenticator = new UserGoogleAuthenticatorEntity($this, $secret);
}
}
/**
* @param UserGoogleAuthenticatorEntity|null $googleAuthenticator
*/
public function setGoogleAuthenticator(?UserGoogleAuthenticatorEntity $googleAuthenticator): void
{
$this->googleAuthenticator = $googleAuthenticator;
}
/**
* @return UserGoogleAuthenticatorEntity|null
*/
public function getGoogleAuthenticator(): ?UserGoogleAuthenticatorEntity
{
return $this->googleAuthenticator;
}
/**
* Clear GA code
*/
public function deleteGoogleAuthenticator(): void
{
$this->googleAuthenticator = null;
}
/**
* @param UserSsoEntity|null $userSso
*/
public function setUserSso(?UserSsoEntity $userSso): void
{
$this->userSso = $userSso;
}
/**
* @return UserSsoEntity|null
*/
public function getUserSso(): ?UserSsoEntity
{
return $this->userSso;
}
/**
* @return Collection
*/
public function getOrganizationTags(): Collection
{
return $this->organizationTags;
}
/**
* Add organization tag
*
* @param OrganizationTagEntity $organizationTag
*/
public function addOrganizationTag(OrganizationTagEntity $organizationTag): void
{
if (!$this->organizationTags->contains($organizationTag)) {
$this->organizationTags->add($organizationTag);
}
}
/**
* @param OrganizationTagEntity $organizationTag
* @return void
*/
public function removeOrganizationTag(OrganizationTagEntity $organizationTag): void
{
if ($this->organizationTags->contains($organizationTag)) {
$this->organizationTags->removeElement($organizationTag);
}
}
/**
* @return void
*/
public function clearOrganizationTag(): void
{
$this->organizationTags = new ArrayCollection();
}
public function clearUserCategories(): void
{
$this->userCategories = new ArrayCollection();
}
/**
* @return Collection
*/
public function getUserCategories(): Collection
{
return $this->userCategories;
}
/**
* @param Collection $userCategories
*/
public function setUserCategories(Collection $userCategories): void
{
$this->userCategories = $userCategories;
}
/**
* @param string $calendarLayout
*/
public function setCalendarLayout(string $calendarLayout): void
{
$this->calendarLayout = $calendarLayout;
}
/**
* @return string
*/
public function getCalendarLayout(): string
{
return $this->calendarLayout;
}
/**
* @param bool $hideUnavailableDates
*/
public function setHideUnavailableDates(bool $hideUnavailableDates): void
{
$this->hideUnavailableDates = $hideUnavailableDates;
}
/**
* @return bool
*/
public function isHideUnavailableDates(): bool
{
return $this->hideUnavailableDates;
}
/**
* @param bool $sundayIsFirstDay
*/
public function setSundayIsFirstDay(bool $sundayIsFirstDay): void
{
$this->sundayIsFirstDay = $sundayIsFirstDay;
}
/**
* @return bool
*/
public function isSundayIsFirstDay(): bool
{
return $this->sundayIsFirstDay;
}
/**
* @param bool $requireSetPassword
*/
public function setRequireSetPassword(bool $requireSetPassword): void
{
$this->requireSetPassword = $requireSetPassword;
}
/**
* @return bool
*/
public function isRequireSetPassword(): bool
{
return $this->requireSetPassword;
}
/**
* @return bool
*/
public function isRequireConfirmEmail(): bool
{
return $this->requireConfirmEmail;
}
/**
* @param bool $requireConfirmEmail
*/
public function setRequireConfirmEmail(bool $requireConfirmEmail): void
{
$this->requireConfirmEmail = $requireConfirmEmail;
}
/**
* @param string|null $address
*/
public function setAddress(?string $address): void
{
$this->address = $address;
}
/**
* @return string|null
*/
public function getAddress(): ?string
{
return $this->address;
}
/**
* @return string|null
*/
public function getState(): ?string
{
return $this->state;
}
/**
* @param string|null $state
*/
public function setState(?string $state): void
{
$this->state = $state;
}
/**
* @return string|null
*/
public function getCity(): ?string
{
return $this->city;
}
/**
* @param string|null $city
*/
public function setCity(?string $city): void
{
$this->city = $city;
}
/**
* @return string|null
*/
public function getZip(): ?string
{
return $this->zip;
}
/**
* @param string|null $zip
*/
public function setZip(?string $zip): void
{
$this->zip = $zip;
}
/**
* @return string|null
*/
public function getCountryId(): ?string
{
return $this->countryId;
}
/**
* @param string|null $countryId
*/
public function setCountryId(?string $countryId): void
{
$this->countryId = $countryId;
}
/**
* @return string|null
*/
public function getFormattedAddress(): ?string
{
if ($this->getCountryId()) {
$address = $this->getCountryId();
$addressArr = [
$this->getState(),
$this->getCity(),
$this->getZip(),
$this->getAddress(),
];
foreach ($addressArr as $value) {
if ($value) {
$address .= ', ' . $value;
}
}
} else {
$address = $this->getAddress();
}
return $address;
}
/**
* @return float|null
*/
public function getLat(): ?float
{
return $this->lat;
}
/**
* @param float|null $lat
*/
public function setLat(?float $lat): void
{
$this->lat = $lat;
}
/**
* @return float|null
*/
public function getLng(): ?float
{
return $this->lng;
}
/**
* @param float|null $lng
*/
public function setLng(?float $lng): void
{
$this->lng = $lng;
}
/**
* @param string|null $otherCategory
*/
public function setOtherCategory(?string $otherCategory): void
{
$this->otherCategory = $otherCategory;
}
/**
* @return string|null
*/
public function getOtherCategory(): ?string
{
return $this->otherCategory;
}
/**
* @param bool|null $showAddressInEmail
*/
public function setShowAddressInEmail(?bool $showAddressInEmail): void
{
$this->showAddressInEmail = !!$showAddressInEmail;
}
/**
* @return bool
*/
public function isShowAddressInEmail(): bool
{
return !!$this->showAddressInEmail;
}
/**
* @return UserDTO
*/
public function toDTO(): UserDTO
{
return $this->createUserDto(UserDTO::class);
}
/**
* @return SimpleUserDTO
*/
public function toSimpleDTO(): SimpleUserDTO
{
return new SimpleUserDTO(
$this->getId(),
$this->getEmail(),
$this->getFullName()
);
}
/**
* @return CustomerDetailedDTO
*/
public function toCustomerDto(): CustomerDetailedDTO
{
$dto = $this->createUserDto(CustomerDetailedDTO::class);
// todo add email limit here
//$dto->addCustomerLimit(new CustomerLimitDTO(UserLimitType::TYPE_EMAIL, $this->getUserEmailLimit()));
$expr = Criteria::expr();
$criteria = Criteria::create();
$criteria->andWhere($expr->eq('enabled', true));
/** @var SubscriptionInterface $subscription */
foreach ($this->subscriptions->matching($criteria) as $subscription) {
$dto->addCustomerSubscription($subscription->toCustomerSubscriptionDTO());
if ($subscription->isValid() && $subscription->isEnabled()) {
$dto->withActiveSubscription(true);
}
}
return $dto;
}
/**
* @return bool
*/
public function isSsoLoginAllowed(): bool
{
return $this->userSso instanceof UserSsoEntity && $this->userSso->getLoginType() !== UserSsoLoginType::TYPE_PASSWORD;
}
/**
* @param bool $ssoLoginAllowed
*/
public function setSsoLoginAllowed(bool $ssoLoginAllowed): void
{
if (!$this->userSso) {
$this->userSso = new UserSsoEntity(UserSsoLoginType::TYPE_PASSWORD, $this);
}
if ($this->userSso->getLoginType() !== UserSsoLoginType::TYPE_SSO) {
if ($ssoLoginAllowed) {
$this->userSso->setLoginType(UserSsoLoginType::TYPE_SSO_PASSWORD);
} else {
$this->userSso->setLoginType(UserSsoLoginType::TYPE_PASSWORD);
}
}
}
/**
* @return bool
*/
public function isOnlySsoUser(): bool
{
return $this->getUserSso() && $this->getUserSso()->getLoginType() === UserSsoLoginType::TYPE_SSO;
}
/**
* @param string|null $lastTwoFactorCode
*/
public function setLastTwoFactorCode(?string $lastTwoFactorCode): void
{
$this->lastTwoFactorCode = $lastTwoFactorCode;
}
/**
* @return string|null
*/
public function getLastTwoFactorCode(): ?string
{
return $this->lastTwoFactorCode;
}
/**
* @return Collection|null
*/
public function getUserOAuth(): ?Collection
{
return $this->userOAuth;
}
/**
* @param string $provider
* @return bool
*/
public function hasOAuthProvider(string $provider): bool
{
$criteria = Criteria::create()->where(Criteria::expr()->eq('provider', $provider));
return (bool)$this->userOAuth->matching($criteria)->count();
}
/**
* @param string $provider
* @return UserOAuthEntity|null
*/
public function getOAuthProvider(string $provider): ?UserOAuthEntity
{
$criteria = Criteria::create()->where(Criteria::expr()->eq('provider', $provider));
$oauthProvider = $this->userOAuth->matching($criteria)->first();
return $oauthProvider ?: null;
}
/**
* @return UserEmailUnsubscribeEntity|null
*/
public function getUserEmailUnsubscribe(): ?UserEmailUnsubscribeEntity
{
return $this->userEmailUnsubscribe;
}
/**
* @param UserCancellationPolicyEntity|null $userCancellationPolicy
*/
public function setUserCancellationPolicy(?UserCancellationPolicyEntity $userCancellationPolicy): void
{
$this->userCancellationPolicy = $userCancellationPolicy;
$this->userCancellationPolicy->setUser($this);
}
/**
* @return UserCancellationPolicyEntity|null
*/
public function getUserCancellationPolicy(): ?UserCancellationPolicyEntity
{
return $this->userCancellationPolicy;
}
/**
* @return UserWidgetEntity|null
*/
public function getUserWidget(): ?UserWidgetEntity
{
return $this->userWidget;
}
/**
* @return string
*/
public function getObjectName(): string
{
return $this->getEmail() . ' (' . $this->getSlug() . ')';
}
/**
* @return string
*/
public function getObjectId(): string
{
return (string)$this->getid();
}
/**
* Get current active subscriptions
*
* @param bool $withOrganisationSubscription
* @return array
*/
public function getCurrentSubscriptions(bool $withOrganisationSubscription = true): array
{
$res = [];
if ($this->getDefaultOrganization()) {
/** @var Member $owner */
foreach ($this->getDefaultOrganization()->getOwners() as $owner) {
$res = array_merge($res, $owner->getUser()->getPaidSubscriptions());
}
return $res;
}
$expr = Criteria::expr();
$criteria = Criteria::create();
$criteria
->andWhere($expr->eq('enabled', true))
//->andWhere($expr->eq('status', 'active'))
->andWhere($expr->gte('expireAt', new DateTimeImmutable()))
->andWhere($expr->lte('startDate', new DateTimeImmutable()));
return array_merge($res, $this->subscriptions->matching($criteria)->toArray());
}
/**
* Return user id for subscription
*
* @return string
*/
public function getSubscriptionUserId(): string
{
if ($this->getDefaultOrganization()) {
/** @var Member $owner */
foreach ($this->getDefaultOrganization()->getOwners() as $owner) {
if ($owner->getUser()->hasPaidSubscription()) {
return (string) $owner->getUser()->getId();
}
}
}
return (string) $this->getId();
}
/**
* Return subscription user
*
* @return UserInterface
*/
public function getSubscriptionUser(): UserInterface
{
if ($this->getDefaultOrganization()) {
/** @var Member $owner */
foreach ($this->getDefaultOrganization()->getOwners() as $owner) {
if ($owner->getUser()->hasPaidSubscription()) {
return $owner->getUser();
}
}
}
return $this;
}
/**
* Get user paid subscriptions
*
* @return array
*/
private function getPaidSubscriptions(): array
{
$expr = Criteria::expr();
$criteria = Criteria::create();
$criteria
->andWhere($expr->eq('enabled', true))
//->andWhere($expr->eq('status', 'active'))
->andWhere($expr->gte('expireAt', new DateTimeImmutable()))
->andWhere($expr->lte('startDate', new DateTimeImmutable()))
->andWhere($expr->eq('free', false));
return $this->getSubscriptions()->matching($criteria)->toArray();
}
/**
* @return Collection
*/
public function getSubscriptions(): Collection
{
return $this->subscriptions;
}
/**
* Get current active subscriptions users limit
*
* @return int
*/
public function getSubscriptionUsersLimit(): int
{
$res = 0;
/** @var SubscriptionInterface $subscription */
foreach ($this->getCurrentSubscriptions() as $subscription) {
$res += $subscription->getUsersTotal();
}
return $res;
}
/**
* Get current active subscriptions bookings limit
*
* @return int
*/
public function getSubscriptionBookingsLimit(): int
{
$res = 0;
/** @var SubscriptionInterface $subscription */
foreach ($this->getCurrentSubscriptions() as $subscription) {
$res += $subscription->getBookingsTotal();
}
return $res;
}
/**
* Has paid subscription
*
* @param bool $skipTrial
* @return bool
*/
public function hasPaidSubscription(bool $skipTrial = false): bool
{
/** @var SubscriptionInterface $subscription */
foreach ($this->getCurrentSubscriptions() as $subscription) {
if (!$subscription->isFree()) {
if ($skipTrial && $subscription->isTrial()) {
continue;
}
return true;
}
}
return false;
}
/**
* @return bool
*/
public function hasTrialSubscription(): bool
{
return !empty($this->getTrialSubscriptions());
}
/**
* @return array
*/
public function getTrialSubscriptions(): array
{
$res = [];
$expr = Criteria::expr();
$criteria = Criteria::create();
$criteria->andWhere($expr->eq('trial', true));
$organization = $this->getDefaultOrganization();
if ($organization) {
/** @var Member $owner */
foreach ($organization->getOwners() as $owner) {
$res = array_merge($res, $owner->getUser()->subscriptions->matching($criteria)->toArray());
}
return $res;
}
return array_merge($res, $this->subscriptions->matching($criteria)->toArray());
}
/**
* Is main owner
*
* @return bool
*/
public function isMainOwner(): bool
{
if ($this->getDefaultOrganization()) {
/** @var Member $member */
foreach ($this->getMembers() as $member) {
if ($member->getOrganization()->getId() === $this->getDefaultOrganization()->getId() && $member->getIsMainOwner()) {
return true;
}
}
}
return false;
}
public function isOwner(): bool
{
if ($this->getDefaultOrganization()) {
return $this->getDefaultOrganization()->isOrganizationOwner($this);
}
return false;
}
/**
* @return UserSocialLinkEntity|null
*/
public function getSocialLink(): ?UserSocialLinkEntity
{
return $this->socialLink;
}
/**
* @param UserSocialLinkEntity|null $socialLink
*/
public function setSocialLink(?UserSocialLinkEntity $socialLink): void
{
$this->socialLink = $socialLink;
$this->socialLink->setUser($this);
}
/**
* @return Collection|UserTaxEntity[]
*/
public function getTax(): Collection
{
return $this->tax;
}
/**
* @param BaseUserInterface $user
* @return bool
*/
public function isEqualTo(BaseUserInterface $user)
{
$isEqualTo = parent::isEqualTo($user);
if ($user->isEnabled() !== $this->isEnabled()) {
$isEqualTo = false;
}
return $isEqualTo;
}
/**
* @return Collection
*/
public function getRelatedUsers(): Collection
{
return $this->relatedUsers;
}
/**
* @param UserRelationEntity $relatedUser
*/
public function addRelatedUser(UserRelationEntity $relatedUser): void
{
if (!$this->relatedUsers->contains($relatedUser)) {
$this->relatedUsers->add($relatedUser);
}
}
/**
* @return array|UserInterface[]
*/
public function getChildRelatedUsers(): array
{
$result = [];
foreach ($this->relatedUsers as $relatedUser) {
$result[] = $relatedUser->getChildUser();
}
return $result;
}
/**
* @param UserRelationEntity $entity
* @return bool
*/
public function hasChildRelatedUser(UserRelationEntity $entity): bool
{
foreach ($this->relatedUsers as $relatedUser) {
if ($relatedUser->getChildUser() === $entity->getChildUser()) {
return true;
}
}
return false;
}
/**
* @return string|null
*/
public function getWelcomeTourStep(): ?string
{
return $this->welcomeTourStep;
}
/**
* @param string|null $welcomeTourStep
*/
public function setWelcomeTourStep(?string $welcomeTourStep): void
{
$this->welcomeTourStep = $welcomeTourStep;
}
/**
* @return bool
*/
public function isSecondFactorSkipped(): bool
{
return $this->secondFactorSkipped;
}
/**
* @param bool $secondFactorSkipped
*/
public function setSecondFactorSkipped(bool $secondFactorSkipped): void
{
$this->secondFactorSkipped = $secondFactorSkipped;
}
/**
* @return bool
*/
public function isTutorialSkipped(): bool
{
$releaseDate = new DateTimeImmutable('2024-09-23');
$oneMonthAfterRegistration = clone $this->createdAt;
$oneMonthAfterRegistration = $oneMonthAfterRegistration->modify('+1 month');
// Check if the user registered after the release date and is within the first month of registration
$isNewUser = $this->createdAt > $releaseDate;
$isWithinFirstMonth = new DateTimeImmutable() <= $oneMonthAfterRegistration;
// Return true if the tutorial has been skipped, or the user is not a new user, or if the one-month period has passed
return $this->tutorialSkipped || !$isNewUser || !$isWithinFirstMonth;
}
/**
* @return void
*/
public function skipTutorial(): void
{
$this->tutorialSkipped = true;
}
/**
* {@inheritdoc}
*/
public function serialize()
{
return serialize([
$this->password,
$this->salt,
$this->usernameCanonical,
$this->username,
$this->enabled,
$this->id,
$this->email,
$this->emailCanonical,
$this->address,
$this->state,
$this->city,
$this->zip,
$this->countryId,
$this->lat,
$this->lng,
$this->brandingEnabled,
$this->showAddressInEmail,
$this->fullName,
$this->timezone,
$this->timeFormat,
$this->dateFormat,
$this->userSso,
$this->otherCategory,
]);
}
/**
* {@inheritdoc}
*/
public function unserialize($serialized)
{
$data = unserialize($serialized);
[
$this->password,
$this->salt,
$this->usernameCanonical,
$this->username,
$this->enabled,
$this->id,
$this->email,
$this->emailCanonical,
$this->address,
$this->state,
$this->city,
$this->zip,
$this->countryId,
$this->lat,
$this->lng,
$this->brandingEnabled,
$this->showAddressInEmail,
$this->fullName,
$this->timezone,
$this->timeFormat,
$this->dateFormat,
$this->userSso,
$this->otherCategory,
] = $data;
}
/**
* @param string $class
* @return UserDto|CustomerDetailedDTO
*/
private function createUserDto(string $class): object
{
$phone = $this->getInternationalPhoneNumber();
$organization = $this->getDefaultOrganization();
$connections = [];
foreach ($this->userOAuth as $userOAuth) {
$connections[] = $userOAuth->getProvider();
}
try {
$timezone = $this->getTimezone() ?? 'UTC';
$currentDate = new DateTimeImmutable('now', new DateTimeZone($timezone));
$timezoneOffset = $currentDate->format('P');
} catch (Exception $e) {
$timezone = 'UTC';
$timezoneOffset = '+00:00';
}
return new $class(
$this->getId(),
$this->getUuid(),
$this->getEmail(),
$this->getFullName(),
$this->getSlug(),
$this->getSubscriptionUsersLimit(),
count($this->getAllowedSecondAuthenticationTypes()) > 0,
$this->isEnabled(),
$this->hasPaidSubscription(),
$this->getDateFormat(),
$this->getTimeFormat(),
$timezone,
$timezoneOffset,
$this->getAddress(),
$this->getState(),
$this->getCity(),
$this->getZip(),
$this->getCountryId(),
$this->getLat(),
$this->getLng(),
$this->getDomain(),
$phone ?: null,
$this->getCompanyLogoName(),
$this->getAvatarName(),
$organization ? $organization->toDTO() : null,
$this->getCreatedAt(),
$this->getLastLogin(),
$connections
);
}
}