예제 #1
0
 /**
  * {@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);
 }
예제 #2
0
 /** 
  * 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);
         });
     }
 }
예제 #4
0
 /**
  * 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;
 }
예제 #5
0
 /**
  * {@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']]);
     });
 }
예제 #6
0
 /**
  * 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');
     }
 }
예제 #7
0
 /**
  * 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;
 }
예제 #8
0
 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);
     }
 }
예제 #9
0
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);    
        }*/
});
예제 #10
0
 /**
  * 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');
 }
예제 #11
0
 /**
  * {@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;
 }
예제 #12
0
 /**
  * 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);
 }
예제 #13
0
 public static function getCacheTime()
 {
     return FriendsSettings::get('report_cache', 60);
 }
예제 #14
0
 /**
  * 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()));
 }
예제 #15
0
 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;
 }
예제 #16
0
 /**
  * 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);
 }
예제 #17
0
 /**
  * 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);
     }
 }