text: const mongoose = require('mongoose');
  const _ = require('lodash');
  
  const { Schema } = mongoose;
  
  const mongoSchema = new Schema({
    googleId: {
      type: String,
      required: true,
      unique: true,
    },
    googleToken: {
      access_token: String,
      refresh_token: String,
    },
    createdAt: {
      type: Date,
      required: true,
    },
    email: {
      type: String,
      required: true,
      unique: true,
    },
    isAdmin: {
      type: Boolean,
      default: false,
    },
    displayName: String,
    avatarUrl: String,
  
    isGithubConnected: {
      type: Boolean,
      default: false,
    },
    githubAccessToken: {
      type: String,
    },
    purchasedBookIds: [String],
    freeBookIds: [String],
  });
  
  class UserClass {
    // User's public fields
    static publicFields() {
      return ['id', 'displayName', 'email', 'avatarUrl', 'isAdmin', 'isGithubConnected'];
    }
  
    static async signInOrSignUp({
      googleId, email, googleToken, displayName, avatarUrl,
    }) {
      const user = await this.findOne({ googleId }).select(UserClass.publicFields().join(' '));
  
      if (user) {
        const modifier = {};
        
        if (googleToken.accessToken) {
          modifier.access_token = googleToken.accessToken;
        }
  
        if (googleToken.refreshToken) {
          modifier.refresh_token = googleToken.refreshToken;
        }
  
        if (_.isEmpty(modifier)) {
          return user;
        }
  
        await this.updateOne({ googleId }, { $set: modifier });
  
        return user;
      }
  
      const newUser = await this.create({
        createdAt: new Date(),
        googleId,
        email,
        googleToken,
        displayName,
        avatarUrl,
      });
  
      return _.pick(newUser, UserClass.publicFields());
    }
  }
  
  mongoSchema.loadClass(UserClass);
  
  const User = mongoose.model('User', mongoSchema);
  
  module.exports = User;
  
  