/** * {@inheritDoc} * @see \DMA\Friends\Classes\Notifications\Channels\Channel::configChannel() */ public function configChannel() { // TOOD : get this values for OctoberCMS settings $accountSid = Settings::get('twilio_account_id'); $authToken = Settings::get('twilio_auth_token'); $this->fromNumber = $this->cleanPhone(Settings::get('twilio_default_from_number'), false); $this->client = new Services_Twilio($accountSid, $authToken); }
/** * Call this scope to expire unread notifications * @param mixed $query * @return mixed * Return query unmodified */ public function scopeExpire($query) { $expireQuery = clone $query; $expireDays = Settings::get('kiosk_notification_max_age', 60); $expireDays = empty($expireDays) ? 60 : $expireDays; $expireDate = Carbon::today()->subDays($expireDays); $expireQuery->where("created_at", "<=", $expireDate)->unread()->update(['is_read' => true]); return $query; }
/** * Handle the dma.friends.badge.completed event * @param Badge $badge * The badge model that has just been completed * @param User $user * The user that completed the badge */ public function onBadgeCompleted($badge, $user) { if (Settings::get('send_badge_email')) { $data = ['badge' => $badge, 'user' => $user]; Mail::send('dma.friends::mail.badge', $data, function ($message) use($user) { $message->to($user->email, $user->full_name); }); } }
/** * Certain functionality can be disabled if it is not a kiosk. If kiosk * registration is required then functionality can be disabled * * @return booelan $showAction * if true then kiosk location should be registered to enable functionality * */ public static function enableAction() { $require_location = FriendsSettings::get('require_location', false); if ($require_location) { $location = self::getLocation(); $showAction = $location ? true : false; } else { $showAction = true; } return $showAction; }
/** * {@inheritDoc} */ public function boot() { // Handle locations upon login $this->registerLocation(); // Register timezone settings date_default_timezone_set(Settings::get('timezone', Config::get('app.timezone'))); // Register ServiceProviders App::register('DMA\\Friends\\FriendsServiceProvider'); App::register('Maatwebsite\\Excel\\ExcelServiceProvider'); // Register aliases $alias = AliasLoader::getInstance(); $alias->alias('Excel', 'Maatwebsite\\Excel\\Facades\\Excel'); // Register Event Subscribers $subscriber = new FriendsEventHandler(); Event::subscribe($subscriber); // Bind user and point events to trigger user synchronization with MailChimp MailChimpIntegration::bindEvents(); // Generate barcode_id when a user object is created // TODO: Migrate when user plugin is forked User::creating(function ($user) { if (empty($user->barcode_id)) { $user->barcode_id = substr(md5($user->email), 0, 9); } }); // Extend the user model to support our custom metadata User::extend(function ($model) { $model->hasOne['metadata'] = ['DMA\\Friends\\Models\\Usermeta', 'key' => 'user_id']; $model->hasMany['activityLogs'] = ['DMA\\Friends\\Models\\ActivityLog']; $model->hasMany['bookmarks'] = ['DMA\\Friends\\Models\\Bookmark']; $model->hasMany['notifications'] = ['DMA\\Friends\\Models\\Notification']; $model->hasMany['rates'] = ['DMA\\Friends\\Models\\UserRate']; $model->belongsToMany['activities'] = ['DMA\\Friends\\Models\\Activity', 'table' => 'dma_friends_activity_user', 'user_id', 'activity_id', 'timestamps' => true, 'order' => 'dma_friends_activity_user.created_at desc']; $model->belongsToMany['steps'] = ['DMA\\Friends\\Models\\Step', 'table' => 'dma_friends_step_user', 'user_id', 'step_id', 'timestamps' => true, 'order' => 'dma_friends_step_user.created_at desc']; $model->belongsToMany['badges'] = ['DMA\\Friends\\Models\\Badge', 'table' => 'dma_friends_badge_user', 'user_id', 'badge_id', 'timestamps' => true, 'order' => 'dma_friends_badge_user.created_at desc']; $model->belongsToMany['rewards'] = ['DMA\\Friends\\Models\\Reward', 'table' => 'dma_friends_reward_user', 'user_id', 'reward_id', 'timestamps' => true, 'order' => 'dma_friends_reward_user.created_at desc']; $model->belongsToMany['groups'] = ['DMA\\Friends\\Models\\UserGroup', 'table' => 'dma_friends_users_groups', 'key' => 'user_id', 'foreignKey' => 'group_id', 'pivot' => ['membership_status']]; }); // Extend User fields $context = $this; Event::listen('backend.form.extendFields', function ($widget) use($context) { $context->extendedUserFields($widget); $context->extendedSettingFields($widget); }); Event::listen('backend.list.extendColumns', function ($widget) { if (!$widget->getController() instanceof \RainLab\User\Controllers\Users) { return; } $widget->addColumns(['barcode_id' => ['label' => 'Barcode ID'], 'full_name' => ['label' => 'Full Name', 'relation' => 'metadata', 'sortable' => false, 'select' => "concat(first_name, ' ', last_name)", 'searchable' => true], 'first_name' => ['label' => 'First Name', 'relation' => 'metadata', 'select' => '@first_name', 'searchable' => true], 'last_name' => ['label' => 'Last Name', 'relation' => 'metadata', 'select' => '@last_name', 'searchable' => true], 'points' => ['label' => 'Points'], 'zip' => ['label' => 'Zip'], 'current_member_number' => ['label' => 'Membership ID', 'relation' => 'metadata', 'select' => '@current_member_number']]); }); }
/** * Read and process incomming data from listenable channels * @return void */ public function fire() { $today = Carbon::today(); $lastRun = Settings::get('reset_group_last_run'); if ($lastRun != $today->toDateTimeString()) { $day = strtolower($today->format('l')); $reset_groups_every_day = Settings::get('reset_groups_every_day'); $reset_groups_time = Settings::get('reset_groups_time'); if (in_array($day, $reset_groups_every_day)) { $reset_at = Carbon::parse($reset_groups_time); if ($reset_at->lte(Carbon::now())) { UserGroup::markInactiveGroups(); Settings::set('reset_group_last_run', $today->toDateTimeString()); } } } else { // \Log::info('Has already run'); } }
/** * Take a string of text and determine if it is an assession object * * @param string A string of text to check * * @return mixed boolean, array * boolean False if code is an assession number * array if code is an assession number */ public static function isAssessionNumber($code) { // Artwork API request template URL $baseUrl = FriendsSettings::get('artwork_api_baseurl', false); $query = FriendsSettings::get('artwork_api_endpoint', false); if ($baseUrl && $query) { // Build collection REST API URL $template = rtrim($baseUrl, '/') . '/' . ltrim($query, '/'); // Get Artwork API headers $headers = []; $headerSettings = FriendsSettings::get('artwork_api_headers', []); foreach ($headerSettings as $h) { $key = array_get($h, 'artwork_api_header', Null); $value = array_get($h, 'artwork_api_header_value', Null); if (!is_null($key) && !is_null($value)) { $headers[$key] = $value; } } // Clean code from spaces in case user miss type it $code = str_replace(' ', '', $code); // Get URL $url = sprintf($template, urlencode($code)); \Log::info($url); // Call REST API $response = Request::get($url)->addHeaders($headers)->send(); // TODO: find a way to abstract this into the settings pluging // so is not tide to a specific business logic. For now // this relay on DMA Brain API structure if ($obj = @$response->body->results[0]) { $data = ['object_id' => $obj->id, 'object_number' => $obj->number, 'object_title' => $obj->title]; return $data; } } else { Log::error('Friends setting "artwork_api_baseurl and artwork_api_endpoint" settings are empty. Please configure them in the backend of OctoberCMS.'); } return false; }
public function listen($arguments, Closure $callback) { $bindChannels = []; $inputValidators = []; if (is_string($arguments)) { // 1. if $arguments is string maybe is a single channelKey $bindChannels[] = $arguments; } elseif (is_array($arguments) && !$this->is_assoc($arguments)) { // 2. if $arguments is an array of only string if so // is a list of channels $bindChannels = $arguments; } elseif (is_array($arguments) && $this->is_assoc($arguments)) { // 3. if $arguments is an associative array first position // could be and array of channelKeys or a single channelKey $bindChannels = array_shift($arguments); if (!is_array($bindChannels)) { $bindChannels = [$bindChannels]; } // 4. find input validators requested foreach ($arguments as $inputCode => $args) { if ($class = @$this->inputValidators[$inputCode]) { // Create a new instance of the input validator $class = new \ReflectionClass($class); $args = is_array($args) ? $args : [$args]; $inputValidators[$inputCode] = $class->newInstanceArgs($args); } } } else { throw new Exception(sprintf('Listen arguments are invalid: %s ', $arguments)); } // Filter out inactive and invalid listable channels $activeChannels = Settings::get('active_listenable_channels', []); $validChannels = []; if (!empty($activeChannels)) { foreach ($bindChannels as $key) { $key = strtolower($key); if (in_array($key, $activeChannels)) { if ($ch = @$this->channels[$key]) { $validChannels[] = $key; } else { throw new \Exception('Invalid channel ' . $key); } } } } $bindChannels = $validChannels; // Bind active listenable channel events foreach ($bindChannels as $channelKey) { // Start listen incoming messages for each active channel $channelKey = strtolower($channelKey); $event = "dma.channel.{$channelKey}.incoming.data"; \Event::listen($event, function (array $messages) use($callback, $inputValidators) { foreach ($messages as $message) { $valid = true; $content = $message->getContent(); //Apply input validators $matches = []; foreach ($inputValidators as $code => $input) { $valid = $input->valid($content); if (!$valid) { break; } else { $matches[$code] = $input->getMatches($content); } } // Delegate event if the message is valid if ($valid) { // Add matches $message->setMatches($matches); $callback($message); } } }); // \Log::debug('register: ' . $event); } }
FactoryMuffin::define('DMA\\Friends\\Models\\Location', ['title' => 'word', 'description' => 'optional:text', 'created_at' => 'dateTime|now']); FactoryMuffin::define('DMA\\Friends\\Models\\Reward', ['title' => 'sentence', 'description' => 'optional:text', 'excerpt' => 'optional:text', 'fine_print' => 'optional:text', 'points' => 'randomDigitNotNull', 'image' => 'optional:imageUrl|400;600', 'barcode' => 'randomLetter|3', 'date_begin' => 'optional:dateTime', 'date_end' => 'optional:dateTime', 'days_valid' => 'optional:randomDigit|2', 'inventory' => 'optional:randomDigit|3', 'enable_email' => 'boolean', 'redemption_email' => 'optional:text', 'is_published' => 'boolean', 'is_archived' => 'boolean', 'hidden' => 'boolean', 'created_at' => 'dateTime|now']); FactoryMuffin::define('DMA\\Friends\\Models\\Step', ['title' => 'sentence', 'created_at' => 'dateTime|now', 'updated_at' => 'dateTime|now']); FactoryMuffin::define('RainLab\\User\\Models\\User', ['name' => 'userName', 'username' => 'userName', 'email' => 'email', 'password' => 'password', 'password_confirmation' => 'password', 'is_activated' => 'boolean', 'activated_at' => 'dateTime', 'last_login' => 'dateTime', 'country' => function ($object, $saved) { return Country::orderByRaw('RAND()')->first(); }, 'state' => function ($object, $saved) { return State::orderByRaw('RAND()')->first(); }, 'created_at' => 'dateTime|now', 'updated_at' => 'dateTime|now', 'phone' => 'optional:phone', 'company' => 'optional:company', 'street_addr' => 'streetAddress', 'city' => 'city', 'zip' => 'postcode', 'points' => 'randomNumber']); FactoryMuffin::define('DMA\\Friends\\Models\\Usermeta', ['first_name' => 'firstName', 'last_name' => 'lastName', 'email_optin' => 'boolean', 'current_member' => 'boolean', 'current_member_number' => 'randomNumber']); /** * Create and empty group * @var DMA\Friends\Models\UserGroup */ FactoryMuffin::define('DMA\\Friends\\Models\\UserGroup', ['owner_id' => 'factory|RainLab\\User\\Models\\User', 'is_active' => 'boolean|100']); /** * Create a group with the maxium of members allow in a group. * The limit is set in the settings of the plugin * @var DMA\Friends\Models\UserGroup */ FactoryMuffin::define('filled:DMA\\Friends\\Models\\UserGroup', [], function ($object) { $limit = Settings::get('maximum_users_per_group'); $members = FactoryMuffin::seed($limit, 'RainLab\\User\\Models\\User'); $members_ids = array_map(function ($m) { return $m->id; }, $members); $object->users()->attach($members_ids); /* forEach($members as $user){ $object->addUser($user); }*/ });
/** * Test if user has available memberships left * * @param RainLab\User\Models\User $user * @return boolean */ public static function hasAvailableMemberships($user) { $memberships = self::getActiveMembershipsCount($user); return $memberships < Settings::get('maximum_user_group_memberships'); }
/** * {@inheritDoc} * @see \DMA\Friends\Classes\Notifications\Channels\Listenable::readChannel() */ public function read() { //https://api.twitter.com/1.1/search/tweets.json $url = 'https://api.twitter.com/1.1/search/tweets.json'; $requestMethod = 'GET'; $getfield = '?q=' . Settings::get('twitter_search_hashtag'); $maxId = Null; if ($sinceId = Settings::set('twitter_since_id') && ($maxId = Settings::get('twitter_max_id'))) { $getfield = $getfield . '&since_id=' . $sinceId; $getfield = $getfield . '&max_id=' . $maxId; } $client = $this->getClient(); $response = $client->setGetfield($getfield)->buildOauth($url, $requestMethod)->performRequest(); // Convert results to php objects $result = json_decode($response); // Convert tweets into messages $tweetIds = []; $messages = []; foreach ($result->statuses as $tweet) { $tweetId = $tweet->id; // Because max_id is also includes the tweet that we have already // processed if max_id is present we remove this tweet from the messages. if ($tweetId != $maxId) { $tweetIds[] = $tweet->id; $msg = new IncomingMessage($this->getKey()); $msg->from($tweet->user->id, $tweet->user->name); $msg->setContent($tweet->text); $messages[] = $msg; } } // Get max_id and since_id // Further information on this Twitter parameters go to // https://dev.twitter.com/rest/public/timelines Settings::set('twitter_max_id', min($tweetIds)); Settings::set('twitter_since_id', max($tweetIds)); return $messages; }
/** * Print a valid coupon based on a reward * @param Reward $reward * The reward model that the coupon is being printed for */ public function printCoupon(Reward $reward) { $this->init(Settings::get('coupon_width'), Settings::get('coupon_height'), Settings::get('coupon_orientation')); $expires = date('m-d-Y', strtotime("+" . $reward->days_valid . " days")); $logo = $this->getLogoPath(); $this->pdf->Image($logo, 8, 1, -170); $this->pdf->Ln(14); $this->pdf->SetFont('Arial', 'B', 6); $this->pdf->setX(8); $this->pdf->Write(4, $reward->fine_print); $this->pdf->Ln(6); $this->pdf->SetFont('Arial', 'B', 8); $this->pdf->setY($this->pdf->getY()); $this->pdf->setX(7); $this->pdf->Write(8, "Expires: " . $expires); //Expiration Date $this->pdf->Ln(7); $this->pdf->setX(8); $this->pdf->Code39(8, $this->pdf->getY(), $reward->barcode); //Bar Code $this->pdf->Ln(8); $this->pdf->setX(8); $this->pdf->SetFont('Arial', 'B', 8); $this->pdf->setY($this->pdf->getY() + 8); $this->pdf->setX(8); $this->pdf->Write(8, Lang::get('dma.friends::lang.rewards.couponText')); $this->pdf->setX(8); $this->pdf->Write(14, ' '); $this->doPrint($this->location->printer_reward); }
public static function getCacheTime() { return FriendsSettings::get('report_cache', 60); }
/** * Test Limit group size. */ public function testGroupLimitSize() { // Create and pre-filled group $group = FactoryMuffin::create('filled:DMA\\Friends\\Models\\UserGroup'); // Group limit from settings $limit = Settings::get('maximum_users_per_group'); $this->assertEquals($limit, count($group->getUsers())); // Add new user and expect an exception // Create member instances $user = FactoryMuffin::create('RainLab\\User\\Models\\User'); $this->assertFalse($group->addUser($user)); // Test that the new user were not added $this->assertEquals($limit, count($group->getUsers())); // Test an user reject invited so a new user can be invited $group->rejectMembership($group->users[0]); // Append new user $this->assertTrue($group->addUser($user)); // Test that the new user were not added $this->assertEquals($limit, count($group->getUsers())); }
private function getExtraSettings() { $extra = []; // Get array of extra settings configured in OctoberCMS backend $raw = FriendsSettings::get('rest_api_extra_settings', []); foreach ($raw as $grp) { $name = $grp['rest_api_group_settings']; $values = $grp['rest_api_group_values']; $name = $this->normalizeKeyNames($name); // Convert group values into a dictionary foreach ($values as $pair) { $key = $pair['rest_api_group_key']; $value = $pair['rest_api_group_value']; $key = $this->normalizeKeyNames($key); $extra[$name][$key] = $value; } } return $extra; }
/** * Ajax handler for adding members */ public function onAdd() { $users = post('users', []); $maxUsers = Settings::get('maximum_users_per_group'); if (count($users) >= $maxUsers) { //trans('dma.friends::lang.group.invalid_activation_code') throw new \Exception(sprintf('Sorry only %s members per group are allowed.', $maxUsers)); } // Add to group $group = $this->getGroup(); if (($newUser = post('newUser')) != '') { $user = User::where($this->getLoginAttr(), '=', $newUser)->first(); if ($user) { $group->addUser($user); } else { throw new \Exception('User not found.'); } } // Updated list of users and other vars $this->prepareVars($group); }
/** * Register events in the the platform that should trigger * and Update or creation a member in the configured * Mailchimp list */ public function bindEvents() { if (!FriendSettings::get('mailchimp_integration', false)) { return; } // Friends platform events $events = ['dma.friends.user.pointsEarned', 'dma.friends.user.pointsRemoved']; // Bind update or create events for the following models $models = ['RainLab\\User\\Models\\User' => [], 'DMA\\Friends\\Models\\Usermeta' => ['relUser' => 'user']]; foreach ($models as $model => $options) { $events[] = 'eloquent.created: ' . $model; $events[] = 'eloquent.updated: ' . $model; } $context = $this; foreach ($events as $evt) { $fn = function () use($context, $models, $evt) { // TODO : How to detect multiple events of the same user // within an transaction. eg. Register a user fires 10 events // This causes 10 individual calls to Mailchimp $args = func_get_args(); // First parameter should a model instance // but just in case we validated it exists if ($instance = @$args[0]) { Log::debug('called ' . $evt); Log::debug(get_class($instance)); $instanceClass = get_class($instance); $user = $instance; if ($instanceClass != 'RainLab\\User\\Models\\User') { // Get user relation field from the model if ($relUser = @$models[$instanceClass]['relUser']) { $user = $instance->{$relUser}; } } if ($user) { $mailchimpMemberUID = $user->email; if ($context->startsWith($evt, 'eloquent.updated')) { // Detect if user change email if ($newEmail = array_get($user->getDirty(), 'email', Null)) { $mailchimpMemberUID = $instance->getOriginal('email'); } } // This events should call Mailchimp only if the $user model has a metadata model // because the metadata model contains the email_optin status // and name of the user. // In some cases is possible that the user has already data in the metadata table // but the user reference in memory is not updated yet. So the following if stament // tries to address the issue. if (!$user->metadata) { // Try to reload the user model from the database // only if is not an user eloquent model event // this is because we could be too earlier in the creation of the user // but if a not eloquent event is trigger is because the user // is fully created but the reference in memory is outdated //if (!$context->startsWith($evt, 'eloquent')){ $user = $user->fresh(); //} } if ($user->metadata) { // Updated or create a member in mailchimp list $context->syncMemberToMailChimp($mailchimpMemberUID, $user); } } } }; // Start listening this event Event::listen($evt, $fn); } }