<commit_before><?php

/*
 * FileSender www.filesender.org
 * 
 * Copyright (c) 2009-2012, AARNet, Belnet, HEAnet, SURFnet, UNINETT
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * *    Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * *    Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * *    Neither the name of AARNet, Belnet, HEAnet, SURFnet and UNINETT nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Require environment (fatal)
if(!defined('FILESENDER_BASE')) die('Missing environment');

/**
 * Represents an user in database
 */
class Guest extends DBObject {
    /**
     * Database map
     */
    protected static $dataMap = array(
        'id' => array(
            'type' => 'uint',
            'size' => 'medium',
            'primary' => true,
            'autoinc' => true
        ),
        'user_id' => array(
            'type' => 'string',
            'size' => 255
        ),
        'user_email' => array(
            'type' => 'string',
            'size' => 250
        ),
        'token' => array(
            'type' => 'string',
            'size' => 60,
            'unique' => true
        ),
        'email' => array(
            'type' => 'string',
            'size' => 255
        ),
        'transfer_count' => array(
            'type' => 'uint',
            'size' => 'medium'
        ),
        'subject' => array(
            'type' => 'string',
            'size' => 255,
            'null' => true
        ),
        'message' => array(
            'type' => 'text',
            'null' => true
        ),
        'options' => array(
            'type' => 'text',
            'transform' => 'json'
        ),
        'status' => array(
            'type' => 'string',
            'size' => 32
        ),
        'created' => array(
            'type' => 'datetime'
        ),
        'expires' => array(
            'type' => 'datetime'
        ),
        'last_activity' => array(
            'type' => 'datetime'
        )
    );
    
    /**
     * Set selectors
     */
    const AVAILABLE = "status = 'available' ORDER BY created DESC";
    const EXPIRED = "expires < :date ORDER BY expires ASC";
    const FROM_USER = "user_id = :user_id AND status = 'available' ORDER BY created DESC";
    
    /**
     * Properties
     */
    protected $id = null;
    protected $user_id = null;
    protected $user_email = null;
    protected $token = null;
    protected $email = null;
    protected $transfer_count = 0;
    protected $subject = null;
    protected $message = null;
    protected $options = null;
    protected $status = null;
    protected $created = 0;
    protected $expires = 0;
    protected $last_activity = 0;
    
    /**
     * Cache
     */
    private $transfersCache = null;
    private $trackingEventsCache = null;
    
    /**
     * Constructor
     * 
     * @param integer $id identifier of guest to load from database (null if loading not wanted)
     * @param array $data data to create the guest from (if already fetched from database)
     * 
     * @throws GuestNotFoundException
     */
    protected function __construct($id = null, $data = null) {
        if(!is_null($id)) {
            $statement = DBI::prepare('SELECT * FROM '.self::getDBTable().' WHERE id = :id');
            $statement->execute(array(':id' => $id));
            $data = $statement->fetch();
            if(!$data) throw new GuestNotFoundException('id = '.$id);
        }
        
        if($data) $this->fillFromDBData($data);
    }
    
    /**
     * Create a new guest
     * 
     * @param integer $recipient recipient email, mandatory
     * @param integer $from sender email
     * 
     * @return Guest
     */
    public static function create($recipient, $from = null) {
        $guest = new self();
        $time = time();
        
        $guest->user_id = Auth::user()->id;
        $guest->__set('user_email', $from ? $from : Auth::user()->email);
        $guest->__set('email', $recipient); // Throws
        
        $guest->status = GuestStatuses::AVAILABLE;
        $guest->created = $time;
        
        // Generate token until it is indeed unique
        $guest->token = Utilities::generateUID(function($token) {
            $statement = DBI::prepare('SELECT * FROM '.Guest::getDBTable().' WHERE token = :token');
            $statement->execute(array(':token' => $token));
            $data = $statement->fetch();
            return !$data;
        });
        
        return $guest;
    }
    
    /**
     * Get default expire date
     * 
     * @return int timestamp
     */
    public static function getDefaultExpire() {
        $days = Config::get('default_guest_days_valid');
        if(!$days) $days = Config::get('default_transfer_days_valid');
        
        return strtotime('+'.$days.' day');
    }
    
    /**
     * Get max expire date
     * 
     * @return int timestamp
     */
    public static function getMaxExpire() {
        $days = Config::get('max_guest_days_valid');
        if(!$days) $days = Config::get('max_transfer_days_valid');
        
        if(!$days) $days = Config::get('default_daysvalid'); // @deprecated legacy
        
        return strtotime('+'.$days.' day');
    }
    
    /**
     * Get expired guests
     * 
     * @return array of Guest
     */
    public static function allExpired() {
        return self::all(self::EXPIRED, array(':date' => date('Y-m-d')));
    }
    
    /**
     * Get guests from user
     * 
     * @param mixed $user User or user id
     * 
     * @return array of Guests
     */
    public static function fromUser($user) {
        if($user instanceof User) $user = $user->id;
        
        return self::all(self::FROM_USER, array(':user_id' => $user));
    }
    
    /**
     * Loads guest from token
     * 
     * @param string $token the token
     * 
     * @throws RecipientNotFoundException
     * 
     * @return Guest
     */
    public static function fromToken($token) {
        $statement = DBI::prepare('SELECT * FROM '.self::getDBTable().' WHERE token = :token');
        $statement->execute(array(':token' => $token));
        $data = $statement->fetch();
        if(!$data) throw new GuestNotFoundException('token = '.$token);
        
        $guest = self::fromData($data['id'], $data);
        
        return $guest;
    }
    
    /**
     * Check if user owns current gueest
     * 
     * @param miwed $user User or user id to compare with
     * 
     * @return bool
     */
    public function isOwner($user) {
        return $this->owner->is($user);
    }
    
    /**
     * Set guest as available, sends notifications
     */
    public function makeAvailable() {
        $this->status = GuestStatuses::AVAILABLE;
        $this->save();
        
        Logger::logActivity(LogEventTypes::GUEST_CREATED, $this);
        
        $this->notify(true);
    }<commit_msg>Save guests as frequent recipients<commit_after><?php

/*
 * FileSender www.filesender.org
 * 
 * Copyright (c) 2009-2012, AARNet, Belnet, HEAnet, SURFnet, UNINETT
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * *    Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * *    Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * *    Neither the name of AARNet, Belnet, HEAnet, SURFnet and UNINETT nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Require environment (fatal)
if(!defined('FILESENDER_BASE')) die('Missing environment');

/**
 * Represents an user in database
 */
class Guest extends DBObject {
    /**
     * Database map
     */
    protected static $dataMap = array(
        'id' => array(
            'type' => 'uint',
            'size' => 'medium',
            'primary' => true,
            'autoinc' => true
        ),
        'user_id' => array(
            'type' => 'string',
            'size' => 255
        ),
        'user_email' => array(
            'type' => 'string',
            'size' => 250
        ),
        'token' => array(
            'type' => 'string',
            'size' => 60,
            'unique' => true
        ),
        'email' => array(
            'type' => 'string',
            'size' => 255
        ),
        'transfer_count' => array(
            'type' => 'uint',
            'size' => 'medium'
        ),
        'subject' => array(
            'type' => 'string',
            'size' => 255,
            'null' => true
        ),
        'message' => array(
            'type' => 'text',
            'null' => true
        ),
        'options' => array(
            'type' => 'text',
            'transform' => 'json'
        ),
        'status' => array(
            'type' => 'string',
            'size' => 32
        ),
        'created' => array(
            'type' => 'datetime'
        ),
        'expires' => array(
            'type' => 'datetime'
        ),
        'last_activity' => array(
            'type' => 'datetime'
        )
    );
    
    /**
     * Set selectors
     */
    const AVAILABLE = "status = 'available' ORDER BY created DESC";
    const EXPIRED = "expires < :date ORDER BY expires ASC";
    const FROM_USER = "user_id = :user_id AND status = 'available' ORDER BY created DESC";
    
    /**
     * Properties
     */
    protected $id = null;
    protected $user_id = null;
    protected $user_email = null;
    protected $token = null;
    protected $email = null;
    protected $transfer_count = 0;
    protected $subject = null;
    protected $message = null;
    protected $options = null;
    protected $status = null;
    protected $created = 0;
    protected $expires = 0;
    protected $last_activity = 0;
    
    /**
     * Cache
     */
    private $transfersCache = null;
    private $trackingEventsCache = null;
    
    /**
     * Constructor
     * 
     * @param integer $id identifier of guest to load from database (null if loading not wanted)
     * @param array $data data to create the guest from (if already fetched from database)
     * 
     * @throws GuestNotFoundException
     */
    protected function __construct($id = null, $data = null) {
        if(!is_null($id)) {
            $statement = DBI::prepare('SELECT * FROM '.self::getDBTable().' WHERE id = :id');
            $statement->execute(array(':id' => $id));
            $data = $statement->fetch();
            if(!$data) throw new GuestNotFoundException('id = '.$id);
        }
        
        if($data) $this->fillFromDBData($data);
    }
    
    /**
     * Create a new guest
     * 
     * @param integer $recipient recipient email, mandatory
     * @param integer $from sender email
     * 
     * @return Guest
     */
    public static function create($recipient, $from = null) {
        $guest = new self();
        $time = time();
        
        $guest->user_id = Auth::user()->id;
        $guest->__set('user_email', $from ? $from : Auth::user()->email);
        $guest->__set('email', $recipient); // Throws
        
        $guest->status = GuestStatuses::AVAILABLE;
        $guest->created = $time;
        
        // Generate token until it is indeed unique
        $guest->token = Utilities::generateUID(function($token) {
            $statement = DBI::prepare('SELECT * FROM '.Guest::getDBTable().' WHERE token = :token');
            $statement->execute(array(':token' => $token));
            $data = $statement->fetch();
            return !$data;
        });
        
        return $guest;
    }
    
    /**
     * Get default expire date
     * 
     * @return int timestamp
     */
    public static function getDefaultExpire() {
        $days = Config::get('default_guest_days_valid');
        if(!$days) $days = Config::get('default_transfer_days_valid');
        
        return strtotime('+'.$days.' day');
    }
    
    /**
     * Get max expire date
     * 
     * @return int timestamp
     */
    public static function getMaxExpire() {
        $days = Config::get('max_guest_days_valid');
        if(!$days) $days = Config::get('max_transfer_days_valid');
        
        if(!$days) $days = Config::get('default_daysvalid'); // @deprecated legacy
        
        return strtotime('+'.$days.' day');
    }
    
    /**
     * Get expired guests
     * 
     * @return array of Guest
     */
    public static function allExpired() {
        return self::all(self::EXPIRED, array(':date' => date('Y-m-d')));
    }
    
    /**
     * Get guests from user
     * 
     * @param mixed $user User or user id
     * 
     * @return array of Guests
     */
    public static function fromUser($user) {
        if($user instanceof User) $user = $user->id;
        
        return self::all(self::FROM_USER, array(':user_id' => $user));
    }
    
    /**
     * Loads guest from token
     * 
     * @param string $token the token
     * 
     * @throws RecipientNotFoundException
     * 
     * @return Guest
     */
    public static function fromToken($token) {
        $statement = DBI::prepare('SELECT * FROM '.self::getDBTable().' WHERE token = :token');
        $statement->execute(array(':token' => $token));
        $data = $statement->fetch();
        if(!$data) throw new GuestNotFoundException('token = '.$token);
        
        $guest = self::fromData($data['id'], $data);
        
        return $guest;
    }
    
    /**
     * Check if user owns current gueest
     * 
     * @param miwed $user User or user id to compare with
     * 
     * @return bool
     */
    public function isOwner($user) {
        return $this->owner->is($user);
    }
    
    /**
     * Set guest as available, sends notifications
     */
    public function makeAvailable() {
        $this->status = GuestStatuses::AVAILABLE;
        $this->save();
        
        Auth::user()->saveFrequentRecipients(array($this->email));
        
        Logger::logActivity(LogEventTypes::GUEST_CREATED, $this);
        
        $this->notify(true);
    }
{'fraction_non_alphanumeric': 0.12849740932642487, 'fraction_numerical': 0.003413593416641268, 'mean_word_length': 2.060249953366909, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 137, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2984852', 'n_tokens_mistral': 4772, 'n_tokens_neox': 4549, 'n_words': 1387}