group.js 10.6 KB
Newer Older
DCloud_JSON's avatar
DCloud_JSON 已提交
1 2 3 4 5 6 7 8 9 10
const {
  db,
  checkParam,
} = require('uni-im-utils')

async function chooseUserIntoGroup(params) {
  let {
    group_id = false,
    groupInfo = {},
    user_ids = [],
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
11 12 13 14
    admin_uids = [],
    // 是否静默加群,会话未读数不显示1
    is_mute = false,
    welcome_message
DCloud_JSON's avatar
DCloud_JSON 已提交
15
  } = params
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
16 17
  
  console.error('is_mute', is_mute);
DCloud_JSON's avatar
DCloud_JSON 已提交
18 19 20 21 22 23 24 25 26

  // 校验参数是否合法
  checkParam(params, {
    required: [],
    type: {
      group_id: ["Boolean", "String"],
      groupInfo: ["Object"],
      user_ids: ["Array"],
      admin_uids: ["Array"],
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
27 28
      is_mute: ["Boolean"],
      welcome_message: ["Object"]
DCloud_JSON's avatar
DCloud_JSON 已提交
29 30 31
    }
  })

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
32
  if ( (user_ids.length + admin_uids.length)  > 499) {
DCloud_JSON's avatar
DCloud_JSON 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    return {
      errSubject: 'uni-im',
      errCode: 2000,
      errMsg: "拉人进群一次不能超过500人,请分多次操作"
    }
  }

  if (Object.keys(groupInfo).length !== 0) {
    checkParam(groupInfo, {
      required: ["name"],
      type: {
        name: ["String"],
        introduction: ["String"],
        avatar_file: ["Object"],
        join_option: ["String"],
        type: ["String"]
      }
    })
    if (groupInfo.avatar_file) {
      checkParam(groupInfo.avatar_file, {
        required: ["url"],
        type: {
          extname: ["String"],
          name: ["String"],
          url: ["String"]
        }
      })
    }
  }

  if (admin_uids.length > 0) {
    admin_uids.forEach(uid => {
      if (user_ids.includes(uid)) {
        throw new Error("参数admin_uids和user_ids的成员不能重复")
      }
    })
  }

  // 存在群 id是拉用户进群,否则是创建新的群并拉新用户进群
  if (!group_id) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
73 74 75 76 77 78 79 80 81 82 83
    
    // todo:为兼容旧版本。这里先去除再插入创建者id到头部
    // 如果 admin_uids 中有创建者,移除
    if (admin_uids.includes(this.current_uid)) {
      admin_uids = admin_uids.filter(uid => uid !== this.current_uid)
    }
    // 如果 user_ids 中有创建者,移除
    if (user_ids.includes(this.current_uid)) {
      user_ids = user_ids.filter(uid => uid !== this.current_uid)
    }
    
DCloud_JSON's avatar
DCloud_JSON 已提交
84
    // 创建群时,需要把创建者(群主)也拉进群
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
85
    admin_uids.unshift(this.current_uid)
DCloud_JSON's avatar
DCloud_JSON 已提交
86 87 88

    // 调用扩展点 before-create-group,允许扩展程序添加群成员
    const { invokeExts } = require('uni-im-ext')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
89
    await invokeExts('before-create-group', admin_uids, this)
DCloud_JSON's avatar
DCloud_JSON 已提交
90
  }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
91 92 93 94
  
  const newMemberCount = user_ids.length + admin_uids.length
  
  // 验证用户是否存在
DCloud_JSON's avatar
DCloud_JSON 已提交
95 96 97 98 99 100
  const dbJQL = uniCloud.databaseForJQL({
    clientInfo: this.clientInfo
  })
  let {
    data: userList
  } = await dbJQL.collection('uni-id-users')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
101
    .where(`"_id" in ${JSON.stringify([...admin_uids,...user_ids])}`)
DCloud_JSON's avatar
DCloud_JSON 已提交
102 103 104 105
    .field('_id,nickname,avatar_file')
    .limit(500)
    .get()

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
106 107 108 109 110 111
  if (userList.length != (admin_uids.length + user_ids.length) ) {
    console.log('userList.length',userList.length);
    console.log('admin_uids.length',admin_uids.length,admin_uids);
    console.log('user_ids.length',user_ids.length,user_ids);
    console.log('this.current_uid',this.current_uid);
    throw {
DCloud_JSON's avatar
DCloud_JSON 已提交
112 113
      errSubject: 'uni-im:chooseUserIntoGroup',
      errCode: 2000,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
114
      errMsg: "参数user_ids或admin_uids错误,用户不存在"
DCloud_JSON's avatar
DCloud_JSON 已提交
115 116 117 118 119 120 121 122 123 124 125 126
    }
  }

  // 如果没有输入群id,就先创建群
  if (!group_id) {
    // 默认群昵称为:群用户昵称拼接 取前30个字符
    if (!groupInfo.name) {
      groupInfo.name = userList.map(user => user.nickname).join(' ').substring(0, 30)
    }
    // console.log({
    // 	name
    // });
127 128 129
    if(groupInfo.user_id === undefined){
      groupInfo.user_id = this.current_uid
    }else if(this.clientInfo.source != "function" && groupInfo.user_id != this.current_uid){
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
130
      throw new Error('非系统内部调用,群主(groupInfo.user_id)的值必须为当前操作者')
131 132
    }
    
DCloud_JSON's avatar
DCloud_JSON 已提交
133 134 135 136 137
    dbJQL.setUser({
      uid: this.current_uid,
      role: ['admin'],
      permission: []
    })
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
138
    groupInfo.member_count = newMemberCount
DCloud_JSON's avatar
DCloud_JSON 已提交
139 140
    let res = await dbJQL.collection('uni-im-group').add(groupInfo)
    group_id = res.id
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
141 142 143 144 145 146 147 148 149
    
    // 把欢迎信息插到uni-im-msg中
    if(welcome_message){
      await db.collection('uni-im-msg').add({
        ...welcome_message,
        create_time: Date.now(),
        conversation_id: 'group_' + group_id
      })
    }
DCloud_JSON's avatar
DCloud_JSON 已提交
150 151
  } else {
    let res = await db.collection('uni-im-group').doc(group_id).get()
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
152
    const source = this.getClientInfo().source
DCloud_JSON's avatar
DCloud_JSON 已提交
153 154
    if (!res.data[0]) {
      throw new Error('群id不存在')
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
155 156 157 158 159 160
    } else if (
      admin_uids.length > 0 && 
      // 群创建者 或 通过云函数中间件调用,才能传递参数admin_uids
      source != 'function' &&
      res.data[0].user_id != this.current_uid
    ) {
DCloud_JSON's avatar
DCloud_JSON 已提交
161 162 163
      throw new Error("非群创建者,不可传递参数参数admin_uids")
    }
  }
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
  
  // TODO:由于支付宝云版uniCloud,唯一索引插入数据并不会抛出异常,所以这里要先查询是否已经在群里
  let hasInGroup = await db.collection('uni-im-group-member')
    .where({
      group_id,
      user_id: db.command.in([...admin_uids, ...user_ids])
    })
    .get()
  if (hasInGroup.data.length > 0) {
    let hasInGroupUserIds = hasInGroup.data.map(item => item.user_id)
    throw {
      errSubject: 'uni-im',
      errCode: 2000,
      errMsg: '用户' + hasInGroupUserIds.join(',') + '已经在群里'
    }
  }
DCloud_JSON's avatar
DCloud_JSON 已提交
180 181 182 183

  const now_timestamp = Date.now()
  // 1. 设为群成员
  let groupMemberList = []
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
184 185
  groupMemberList.push(...createMemberList.call(this,admin_uids, ['admin']))
  groupMemberList.push(...createMemberList.call(this,user_ids))
DCloud_JSON's avatar
DCloud_JSON 已提交
186

DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
187
  function createMemberList(userIdList, role = []) {
DCloud_JSON's avatar
DCloud_JSON 已提交
188 189 190 191
    return userIdList.map(user_id => {
      return {
        group_id,
        user_id,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
192 193
        // 设置群成员角色:创建者为群主,其他看传入的角色
        role: user_id === this.current_uid ? ['creator', 'admin'] : role,
DCloud_JSON's avatar
DCloud_JSON 已提交
194 195 196 197 198 199 200 201
        create_time: now_timestamp
      }
    })
  }

  let res;
  try {
    res = await db.collection('uni-im-group-member').add(groupMemberList)
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
202
    // 补充群成员id,方便客户端收到消息后,可直接更新本地的群成员列表
DCloud_JSON's avatar
DCloud_JSON 已提交
203 204 205 206 207
    groupMemberList.forEach((item,index) => {
      item._id = res.ids[index]
    })
    console.log('uni-im-group-member-  res', res);
  } catch (error) {
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
208 209
    console.error('error.message', error.message);
    // 靠数据库的唯一索引,避免重复加群
DCloud_JSON's avatar
DCloud_JSON 已提交
210 211 212 213 214 215 216
    if (error.message.includes("index: user_id_group_id dup")) {
      throw new Error('用户已经在群里')
    } else {
      throw error
    }
  }
  // console.log('uni-im-group-member-  res', res);
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
217 218 219 220 221 222 223 224 225 226 227 228 229 230
  
  
  if(params.group_id){
    // 如果入参有group_id,表示是拉人进群,不是创建群
    // 给群成员总数字段+n
    await db.collection('uni-im-group')
      .where({
        _id: group_id
      })
      .update({
        member_count: db.command.inc(newMemberCount)
      })
  }
  
DCloud_JSON's avatar
DCloud_JSON 已提交
231 232 233 234 235 236 237 238 239

  // 2.给新群成员加上会话表
  let conversationList = groupMemberList.map(({ user_id }) => {
    return {
      group_id,
      id: 'group_' + group_id,
      user_id: user_id,
      type: 2,
      create_time: now_timestamp,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
240 241 242 243 244 245 246 247
      update_time: now_timestamp,
      last_msg_create_time: now_timestamp,
      pinned: false,
      hidden: false,
      mute: false,
      has_unread_group_notification: null,
      unread_count: is_mute ? 0 : 1,
      group_type: groupInfo.type
DCloud_JSON's avatar
DCloud_JSON 已提交
248 249 250 251 252 253 254 255
    }
  })
  res = await db.collection('uni-im-conversation').add(conversationList)

  // 3. 创建”用户加群“的指令型消息,到群聊(通知所有群成员,有用户加入群聊)
  const msgData = {
    body: {
      user_id_list: groupMemberList.map(item => item.user_id),
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
256 257
      new_member_list: groupMemberList,
      group_type: groupInfo.type,
DCloud_JSON's avatar
DCloud_JSON 已提交
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
    },
    action: "join-group",
    type: "system",
    from_uid: "system",
    create_time: now_timestamp,
    conversation_id: "group_" + group_id,
    group_id
  }
  
  res = await db.collection('uni-im-msg').add(msgData)
  _checkForLongMsg(msgData)
  // console.log('res uni-im-msg add', res);
  msgData._id = res.id
  // 更新“所有”此群相关会话列表
  await db.collection('uni-im-conversation')
    .where({
      id: "group_" + group_id
    })
    .update({
      update_time: msgData.create_time,
DCloud_JSON's avatar
3.4.31  
DCloud_JSON 已提交
278
      last_msg_create_time: msgData.create_time,
DCloud_JSON's avatar
DCloud_JSON 已提交
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
      last_msg_note: "新用户加群通知"
    })

  let title = "新用户加群通知",
    content = "用户成功加入群:" + groupInfo.name;
  //通知所有群成员
  const uniImCo = uniCloud.importObject("uni-im-co")
  let pushRes = await uniImCo.sendMsgToGroup({
    pushParam: {
      // 同时发给对方和当前用户自己(包括了他的其他设备,比如web和app、小程序同时登录时,实现消息同步;注:发送此消息的设备会在客户端过滤)
      payload: {
        type: "uni-im",
        data: msgData,
        title, // "收到im消息,在线时显示的标题",
        content // "在线时显示的副标题",
      },
      title, // "收到im消息,离线时显示的标题",
      content //"离线时显示的内容"
    },
    appId: this.clientInfo.appId
  })

  // console.log('uni-im-group-member-  res', res);

  return {
    errSubject: 'uni-im',
    errCode: 0,
    data: {
      pushRes,
      group_id
    },
    errMsg: ''
  }
}

// 拉黑会话
async function addToGroupMenberBlackList({
  user_id,
  group_id
}) {
  // 入参数都不能为空
  if (!user_id || !group_id) {
    throw Error('参数不完整')
  }
  // 判断操作者是否为群主
  let res = await db.collection('uni-im-group-member')
                    .where({
                      group_id,
                      user_id:this.current_uid
                    })
                    .get()
  if( !(res.data[0] && res.data[0].role.includes('admin')) ){
  	throw Error('没有权限')
  }
  res = await db.collection('uni-im-group-member-black')
    .add({
      group_id,
      user_id,
      create_time: Date.now()
    })
  if (res.id) {
    return {
      errCode: 0,
      errMsg: '拉黑成功'
    }
  }else{
    throw Error('拉黑失败')
  }
}

module.exports = {
  chooseUserIntoGroup,
  addToGroupMenberBlackList
}


function _checkForLongMsg(msgData) {
  let bodyStr = JSON.stringify(msgData.body)
  if (bodyStr > 50000) {
    throw new Error('单次消息最长字符长度不得超过50000')
  }
  if (bodyStr.length > 250) {
    switch (msgData.type) {
    case 'rich-text':
      msgData.body = "富文本消息"
      break;
    case 'history':
      msgData.body = "转发的聊天记录"
      break;
    case 'text':
      // 截断,但标识消息为长文本消息,客户端收到此标识,会从数据库中拉取完整消息内容
      msgData.body = msgData.body.slice(0, 50)
      break;
    default:
      msgData.body = `[${msgData.type}]类型消息`
      break;
    }

    msgData.LongMsg = true
  }
}