<commit_before>//
//   Copyright 2014 <NAME> <<EMAIL>>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing,
//   software distributed under the License is distributed on an "AS
//   IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//   express or implied.  See the License for the specific language
//   governing permissions and limitations under the License.
//

'use strict';

const Promise = require('bluebird'),
      Friend = require('../models/friend'),
      notification = require('../lib/notification');

const EPOCH_DATE = new Date(1);

// TBD: Instead of FRIENDS and FRIENDSUPDATE, use ADDFRIENDS

exports.sendFriends = async function(user, sessionId) {
    const command = {
        id: 'FRIENDS',
        reset: true,
        friends: []
    };

    const friendUsers = await getFriendUsers(user);

    for (let friendUser of friendUsers) {
        const last = friendUser.get('lastLogout');
        const online = last === null;

        const friendData = {
            userId: `m${friendUser.id}`,
            online: online
        };

        if (!online) {
            friendData.last = last < EPOCH_DATE ? -1 : Math.floor(last.getTime() / 1000);
        }

        command.friends.push(friendData);
    }

    if (sessionId) {
        await notification.send(user, sessionId, command);
    } else {
        await notification.broadcast(user, command);
    }
};

exports.sendFriendConfirm = async function(user, sessionId) {
    const friendAsDst = await Friend.find({ dstUserId: user.id });

    const friendUsers = friendAsDst.filter(record => record.get('state') === 'pending');

    if (friendUsers.length > 0) {
        // Uses userId property so that related USERS notification is send automatically
        // See lib/notification.js for the details.
        await notification.send(user, sessionId, {
            id: 'FRIENDSCONFIRM',
            friends: friendUsers.map(friendUser => ({ userId: friendUser.gId }))
        });
    }
};

exports.informStateChange = async function(user, eventType) {
    let command = {
        id: 'FRIENDS',
        reset: false,
        friends: [ {
            userId: user.id,
            online: eventType === 'login'
        } ]
    };

    // Zero means the user is currently online
    let ts = 0;

    if (eventType !== 'login') {
        ts = Date.now();
        command.friends[0].last = Math.round(ts / 1000);
    }

    await user.set('lastLogout', ts);

    const friendUsers = await getFriendUsers(user);

    for (let friendUser of friendUsers) {
        await notification.broadcast(friendUser, command);
    }
};

exports.removeUser = async function(user) {
    const [ friendAsSrc, friendAsDst ] = await Promise.all([
        Friend.find({ srcUserId: user.id }),
        Friend.find({ dstUserId: user.id })
    ]);

    const friends = friendAsSrc.concat(friendAsDst);

    for (let friend of friends) {
        await friend.delete();
    }
};

async function getFriendUsers(user) {
    const [ friendAsSrc, friendAsDst ] = await Promise.all([
        Friend.find({ srcUserId: user.id }),
        Friend.find({ dstUserId: user.id })
    ]);

    return friendAsSrc.concat(friendAsDst).filter(record => record.get('state') === 'active');
}<commit_msg>Add new friends service methods<commit_after>//
//   Copyright 2014 <NAME> <<EMAIL>>
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing,
//   software distributed under the License is distributed on an "AS
//   IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//   express or implied.  See the License for the specific language
//   governing permissions and limitations under the License.
//

'use strict';

const Promise = require('bluebird'),
      Friend = require('../models/friend'),
      notification = require('../lib/notification');

const EPOCH_DATE = new Date(1);

// TBD: Instead of FRIENDS and FRIENDSUPDATE, use ADDFRIENDS

exports.sendFriends = async function(user, sessionId) {
    sendFriends(user, sessionId);
};

exports.sendFriendConfirm = async function(user, sessionId) {
    const friendAsDst = await Friend.find({ dstUserId: user.id });

    const friendUsers = friendAsDst.filter(record => record.get('state') === 'pending');

    if (friendUsers.length > 0) {
        // Uses userId property so that related USERS notification is send automatically
        // See lib/notification.js for the details.
        await notification.send(user, sessionId, {
            id: 'FRIENDSCONFIRM',
            friends: friendUsers.map(friendUser => ({ userId: friendUser.gId }))
        });
    }
};

exports.informStateChange = async function(user, eventType) {
    let command = {
        id: 'FRIENDS',
        reset: false,
        friends: [ {
            userId: user.id,
            online: eventType === 'login'
        } ]
    };

    // Zero means the user is currently online
    let ts = 0;

    if (eventType !== 'login') {
        ts = Date.now();
        command.friends[0].last = Math.round(ts / 1000);
    }

    await user.set('lastLogout', ts);

    const friendUsers = await getFriendUsers(user);

    for (let friendUser of friendUsers) {
        await notification.broadcast(friendUser, command);
    }
};

exports.createPending = async function(user, friendUser) {
    await Friend.create({
        srcUserId: user.id,
        dstUserId: friendUser.id,
        state: 'asking'
    });

    await Friend.create({
        srcUserId: friendUser.id,
        dstUserId: user.id,
        state: 'pending'
    });
};

exports.activateFriends = async function(user, friendUser) {
    const srcFriend = await Friend.findFirst({
        srcUserId: user.id,
        dstUserId: friendUser.id
    })

    const dstFriend = await Friend.findFirst({
        srcUserId: friendUser.id,
        dstUserId: user.id
    })

    await srcFriend.set({ state: 'active' });
    await dstFriend.set({ state: 'active' });

    // Inform both parties
    await sendFriends(user);
    await sendFriends(friendUser);
}

exports.removeFriends = async function(user, friendUser) {
    const srcFriend = await Friend.findFirst({
        srcUserId: user.id,
        dstUserId: friendUser.id
    })

    const dstFriend = await Friend.findFirst({
        srcUserId: friendUser.id,
        dstUserId: user.id
    })

    await srcFriend.delete();
    await dstFriend.delete();
}

exports.removeUser = async function(user) {
    const [ friendAsSrc, friendAsDst ] = await Promise.all([
        Friend.find({ srcUserId: user.id }),
        Friend.find({ dstUserId: user.id })
    ]);

    const friends = friendAsSrc.concat(friendAsDst);

    for (let friend of friends) {
        await friend.delete();
    }
};

async function sendFriends(user, sessionId) {
    const command = {
        id: 'FRIENDS',
        reset: true,
        friends: []
    };

    const friendUsers = await getFriendUsers(user);

    for (let friendUser of friendUsers) {
        const last = friendUser.get('lastLogout');
        const online = last === null;

        const friendData = {
            userId: `m${friendUser.id}`,
            online: online
        };

        if (!online) {
            friendData.last = last < EPOCH_DATE ? -1 : Math.floor(last.getTime() / 1000);
        }

        command.friends.push(friendData);
    }

    if (sessionId) {
        await notification.send(user, sessionId, command);
    } else {
        await notification.broadcast(user, command);
    }
}

async function getFriendUsers(user) {
    const [ friendAsSrc, friendAsDst ] = await Promise.all([
        Friend.find({ srcUserId: user.id }),
        Friend.find({ dstUserId: user.id })
    ]);

    return friendAsSrc.concat(friendAsDst).filter(record => record.get('state') === 'active');
}
{'fraction_non_alphanumeric': 0.12342233009708738, 'fraction_numerical': 0.005097087378640777, 'mean_word_length': 2.541469703480877, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 17, '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': '2943624', 'n_tokens_mistral': 2419, 'n_tokens_neox': 2406, 'n_words': 669}