GroupAnnoucement (#1141)

* Add more comment about GroupAnnouncement.kt

* Edit comment about GroupAnnouncement.kt
Provide experimental api

* Api Dump

* After review

* Change to interface and API dump

* More change

* More change

* More more change

* Some change

* api dump

* Fix name

* Redesign Announcement public api

* Edit comment about GroupAnnouncement.kt
Provide experimental api

* After review

* Change to interface and API dump

* More change

* Modify to extension fun

* Fix sendAnnouncement and change place

* Change Group.deleteAnnouncement to group companion

* fix publish

* Api dump

* Reformat code

* Add `@since 2.7`

* Fix build

Co-authored-by: Him188 <Him188@mamoe.net>
This commit is contained in:
Noire 2021-06-24 00:59:53 +08:00 committed by GitHub
parent a8dbd761eb
commit b8de3f77ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 703 additions and 13 deletions

View File

@ -362,6 +362,7 @@ public abstract interface class net/mamoe/mirai/contact/Group : kotlinx/coroutin
public abstract fun getSettings ()Lnet/mamoe/mirai/contact/GroupSettings;
public fun quit ()Z
public abstract fun quit (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun sendAnnouncement$default (Lnet/mamoe/mirai/contact/Group$Companion;Lnet/mamoe/mirai/contact/Group;Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;ILjava/lang/Object;)V
public fun sendMessage (Ljava/lang/String;)Lnet/mamoe/mirai/message/MessageReceipt;
public fun sendMessage (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun sendMessage (Lnet/mamoe/mirai/message/data/Message;)Lnet/mamoe/mirai/message/MessageReceipt;
@ -376,6 +377,8 @@ public abstract interface class net/mamoe/mirai/contact/Group : kotlinx/coroutin
}
public final class net/mamoe/mirai/contact/Group$Companion {
public static synthetic fun sendAnnouncement$default (Lnet/mamoe/mirai/contact/Group$Companion;Lnet/mamoe/mirai/contact/Group;Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;ILjava/lang/Object;)V
public static synthetic fun sendAnnouncement$default (Lnet/mamoe/mirai/contact/Group$Companion;Lnet/mamoe/mirai/contact/Group;Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public final fun setEssenceMessage (Lnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/message/data/MessageChain;)Z
public final fun setEssenceMessage (Lnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/message/data/MessageChain;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
@ -569,6 +572,62 @@ public abstract interface class net/mamoe/mirai/contact/UserOrBot : net/mamoe/mi
public abstract fun nudge ()Lnet/mamoe/mirai/message/action/Nudge;
}
public class net/mamoe/mirai/data/Announcement {
public static final field Companion Lnet/mamoe/mirai/data/Announcement$Companion;
public static final fun create (JLjava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;)Lnet/mamoe/mirai/data/Announcement;
public final fun getBotId ()J
public final fun getMsg ()Ljava/lang/String;
public final fun getParameters ()Lnet/mamoe/mirai/data/AnnouncementParameters;
public final fun getTitle ()Ljava/lang/String;
public synthetic fun publish (Lnet/mamoe/mirai/contact/Group;)Lkotlin/Unit;
public fun publish (Lnet/mamoe/mirai/contact/Group;)V
public final fun publish (Lnet/mamoe/mirai/contact/Group;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class net/mamoe/mirai/data/Announcement$Companion {
public final fun create (JLjava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;)Lnet/mamoe/mirai/data/Announcement;
}
public final class net/mamoe/mirai/data/AnnouncementKt {
public static final fun buildAnnouncementParameters (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/data/AnnouncementParameters;
}
public final class net/mamoe/mirai/data/AnnouncementParameters {
public fun <init> ()V
public final fun builder ()Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun getImage ()[B
public final fun getNeedConfirm ()Z
public final fun getSendToNewMember ()Z
public final fun isPinned ()Z
public final fun isShowEditCard ()Z
public final fun isTip ()Z
}
public final class net/mamoe/mirai/data/AnnouncementParametersBuilder {
public fun <init> ()V
public fun <init> (Lnet/mamoe/mirai/data/AnnouncementParameters;)V
public synthetic fun <init> (Lnet/mamoe/mirai/data/AnnouncementParameters;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun build ()Lnet/mamoe/mirai/data/AnnouncementParameters;
public final fun getImage ()[B
public final fun getNeedConfirm ()Z
public final fun getSendToNewMember ()Z
public final fun image ([B)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun isPinned ()Z
public final fun isShowEditCard ()Z
public final fun isTip ()Z
public final fun needConfirm (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun pinned (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun sendToNewMember (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun setImage ([B)V
public final fun setNeedConfirm (Z)V
public final fun setPinned (Z)V
public final fun setSendToNewMember (Z)V
public final fun setShowEditCard (Z)V
public final fun setTip (Z)V
public final fun showEditCard (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun tip (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
}
public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mirai/data/UserInfo {
public abstract fun getNick ()Ljava/lang/String;
public abstract fun getRemark ()Ljava/lang/String;
@ -870,6 +929,21 @@ public final class net/mamoe/mirai/data/GroupAnnouncement$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public final class net/mamoe/mirai/data/GroupAnnouncementImage$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Lnet/mamoe/mirai/data/GroupAnnouncementImage$$serializer;
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lnet/mamoe/mirai/data/GroupAnnouncementImage;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lnet/mamoe/mirai/data/GroupAnnouncementImage;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}
public final class net/mamoe/mirai/data/GroupAnnouncementImage$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public final class net/mamoe/mirai/data/GroupAnnouncementList$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Lnet/mamoe/mirai/data/GroupAnnouncementList$$serializer;
public static final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor;
@ -1232,6 +1306,14 @@ public final class net/mamoe/mirai/data/OnlineStatus$Companion {
public final fun ofIdOrNull (I)Lnet/mamoe/mirai/data/OnlineStatus;
}
public final class net/mamoe/mirai/data/ReceiveAnnouncement : net/mamoe/mirai/data/Announcement {
public final fun getFid ()Ljava/lang/String;
public final fun getPublishTime ()J
public final fun getReadMemberNumber ()I
public final fun getSenderId ()J
public final fun isAllRead ()Z
}
public abstract interface class net/mamoe/mirai/data/StrangerInfo : net/mamoe/mirai/data/UserInfo {
public abstract fun getFromGroup ()J
public abstract fun getNick ()Ljava/lang/String;

View File

@ -362,6 +362,7 @@ public abstract interface class net/mamoe/mirai/contact/Group : kotlinx/coroutin
public abstract fun getSettings ()Lnet/mamoe/mirai/contact/GroupSettings;
public fun quit ()Z
public abstract fun quit (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun sendAnnouncement$default (Lnet/mamoe/mirai/contact/Group$Companion;Lnet/mamoe/mirai/contact/Group;Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;ILjava/lang/Object;)V
public fun sendMessage (Ljava/lang/String;)Lnet/mamoe/mirai/message/MessageReceipt;
public fun sendMessage (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun sendMessage (Lnet/mamoe/mirai/message/data/Message;)Lnet/mamoe/mirai/message/MessageReceipt;
@ -376,6 +377,8 @@ public abstract interface class net/mamoe/mirai/contact/Group : kotlinx/coroutin
}
public final class net/mamoe/mirai/contact/Group$Companion {
public static synthetic fun sendAnnouncement$default (Lnet/mamoe/mirai/contact/Group$Companion;Lnet/mamoe/mirai/contact/Group;Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;ILjava/lang/Object;)V
public static synthetic fun sendAnnouncement$default (Lnet/mamoe/mirai/contact/Group$Companion;Lnet/mamoe/mirai/contact/Group;Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public final fun setEssenceMessage (Lnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/message/data/MessageChain;)Z
public final fun setEssenceMessage (Lnet/mamoe/mirai/contact/Group;Lnet/mamoe/mirai/message/data/MessageChain;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
@ -569,6 +572,62 @@ public abstract interface class net/mamoe/mirai/contact/UserOrBot : net/mamoe/mi
public abstract fun nudge ()Lnet/mamoe/mirai/message/action/Nudge;
}
public class net/mamoe/mirai/data/Announcement {
public static final field Companion Lnet/mamoe/mirai/data/Announcement$Companion;
public static final fun create (JLjava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;)Lnet/mamoe/mirai/data/Announcement;
public final fun getBotId ()J
public final fun getMsg ()Ljava/lang/String;
public final fun getParameters ()Lnet/mamoe/mirai/data/AnnouncementParameters;
public final fun getTitle ()Ljava/lang/String;
public synthetic fun publish (Lnet/mamoe/mirai/contact/Group;)Lkotlin/Unit;
public fun publish (Lnet/mamoe/mirai/contact/Group;)V
public final fun publish (Lnet/mamoe/mirai/contact/Group;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public final class net/mamoe/mirai/data/Announcement$Companion {
public final fun create (JLjava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/data/AnnouncementParameters;)Lnet/mamoe/mirai/data/Announcement;
}
public final class net/mamoe/mirai/data/AnnouncementKt {
public static final fun buildAnnouncementParameters (Lkotlin/jvm/functions/Function1;)Lnet/mamoe/mirai/data/AnnouncementParameters;
}
public final class net/mamoe/mirai/data/AnnouncementParameters {
public fun <init> ()V
public final fun builder ()Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun getImage ()[B
public final fun getNeedConfirm ()Z
public final fun getSendToNewMember ()Z
public final fun isPinned ()Z
public final fun isShowEditCard ()Z
public final fun isTip ()Z
}
public final class net/mamoe/mirai/data/AnnouncementParametersBuilder {
public fun <init> ()V
public fun <init> (Lnet/mamoe/mirai/data/AnnouncementParameters;)V
public synthetic fun <init> (Lnet/mamoe/mirai/data/AnnouncementParameters;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun build ()Lnet/mamoe/mirai/data/AnnouncementParameters;
public final fun getImage ()[B
public final fun getNeedConfirm ()Z
public final fun getSendToNewMember ()Z
public final fun image ([B)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun isPinned ()Z
public final fun isShowEditCard ()Z
public final fun isTip ()Z
public final fun needConfirm (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun pinned (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun sendToNewMember (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun setImage ([B)V
public final fun setNeedConfirm (Z)V
public final fun setPinned (Z)V
public final fun setSendToNewMember (Z)V
public final fun setShowEditCard (Z)V
public final fun setTip (Z)V
public final fun showEditCard (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
public final fun tip (Z)Lnet/mamoe/mirai/data/AnnouncementParametersBuilder;
}
public abstract interface class net/mamoe/mirai/data/FriendInfo : net/mamoe/mirai/data/UserInfo {
public abstract fun getNick ()Ljava/lang/String;
public abstract fun getRemark ()Ljava/lang/String;
@ -870,6 +929,21 @@ public final class net/mamoe/mirai/data/GroupAnnouncement$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public final class net/mamoe/mirai/data/GroupAnnouncementImage$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Lnet/mamoe/mirai/data/GroupAnnouncementImage$$serializer;
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lnet/mamoe/mirai/data/GroupAnnouncementImage;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lnet/mamoe/mirai/data/GroupAnnouncementImage;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}
public final class net/mamoe/mirai/data/GroupAnnouncementImage$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public final class net/mamoe/mirai/data/GroupAnnouncementList$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Lnet/mamoe/mirai/data/GroupAnnouncementList$$serializer;
public static final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor;
@ -1232,6 +1306,14 @@ public final class net/mamoe/mirai/data/OnlineStatus$Companion {
public final fun ofIdOrNull (I)Lnet/mamoe/mirai/data/OnlineStatus;
}
public final class net/mamoe/mirai/data/ReceiveAnnouncement : net/mamoe/mirai/data/Announcement {
public final fun getFid ()Ljava/lang/String;
public final fun getPublishTime ()J
public final fun getReadMemberNumber ()I
public final fun getSenderId ()J
public final fun isAllRead ()Z
}
public abstract interface class net/mamoe/mirai/data/StrangerInfo : net/mamoe/mirai/data/UserInfo {
public abstract fun getFromGroup ()J
public abstract fun getNick ()Ljava/lang/String;

View File

@ -15,6 +15,7 @@ import kotlinx.coroutines.Job
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.*
import net.mamoe.mirai.utils.ExternalResource
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.WeakRef
import kotlin.annotation.AnnotationTarget.*
@ -141,6 +142,18 @@ public interface LowLevelApiAccessor {
amount: Int = 10
): GroupAnnouncementList
/**
* 上传群公告的所需要的一个图片但不发送
*
*/
@LowLevelApi
@MiraiExperimentalApi
public suspend fun uploadGroupAnnouncementImage(
bot: Bot,
groupId: Long,
resource: ExternalResource
): GroupAnnouncementImage
/**
* 发送群公告
*
@ -154,6 +167,19 @@ public interface LowLevelApiAccessor {
announcement: GroupAnnouncement
): String
/**
* 发送包含图片的群公告
*
* @return 公告的fid
*/
@LowLevelApi
@MiraiExperimentalApi
public suspend fun sendGroupAnnouncementWithImage(
bot: Bot,
groupId: Long,
image: GroupAnnouncementImage,
announcement: GroupAnnouncement
):String
/**
* 删除群公告

View File

@ -12,8 +12,14 @@
package net.mamoe.mirai.contact
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.Bot
import net.mamoe.mirai.Mirai
import net.mamoe.mirai.data.Announcement
import net.mamoe.mirai.data.AnnouncementParameters
import net.mamoe.mirai.data.ReceiveAnnouncement
import net.mamoe.mirai.data.covertToGroupAnnouncement
import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.*
@ -175,6 +181,28 @@ public interface Group : Contact, CoroutineScope, FileSupported {
*/
public suspend fun setEssenceMessage(source: MessageSource): Boolean
/**
* 获取所有群公告列表
*/
@MiraiExperimentalApi
public suspend fun getAnnouncements(): Flow<Announcement>
/**
* 删除一条群公告
* @param fid 公告的id [ReceiveAnnouncement.fid]
*
* @throws PermissionDeniedException 没有权限时抛出
*/
@MiraiExperimentalApi
public suspend fun deleteAnnouncement(fid: String)
/**
* 获取一条群公告
* @param fid 公告的id [ReceiveAnnouncement.fid]
*/
@MiraiExperimentalApi
public suspend fun getAnnouncement(fid: String): ReceiveAnnouncement
public companion object {
/**
* 将一条消息设置为群精华消息, 需要管理员或群主权限.
@ -188,6 +216,39 @@ public interface Group : Contact, CoroutineScope, FileSupported {
@JvmBlockingBridge
@JvmStatic
public suspend fun Group.setEssenceMessage(chain: MessageChain): Boolean = setEssenceMessage(chain.source)
/**
* 发送一个 [Announcement]
*
* @param title 公告标题
* @param msg 公告内容
* @param announcementParameters 公告设置
*/
@MiraiExperimentalApi
@JvmBlockingBridge
@JvmStatic
public suspend fun Group.sendAnnouncement(
title: String,
msg: String,
announcementParameters: AnnouncementParameters = AnnouncementParameters()
) {
checkBotPermission(MemberPermission.ADMINISTRATOR) { "Only administrator have permission to send group announcement" }
Mirai.sendGroupAnnouncement(
bot,
id,
Announcement(bot.id, title, msg, announcementParameters).covertToGroupAnnouncement()
)
}
/**
* 删除一条群公告
* @param receiveAnnouncement 公告 [ReceiveAnnouncement]
*/
@MiraiExperimentalApi
@JvmBlockingBridge
@JvmStatic
public suspend fun Group.deleteAnnouncement(receiveAnnouncement: ReceiveAnnouncement): Unit =
deleteAnnouncement(receiveAnnouncement.fid)
}
}
@ -258,3 +319,4 @@ public inline fun Group.getMemberOrFail(id: Long): NormalMember = getOrFail(id)
* @see Group.botMuteRemaining 剩余禁言时间
*/
public inline val Group.isBotMuted: Boolean get() = this.botMuteRemaining != 0

View File

@ -0,0 +1,312 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("unused")
@file:JvmBlockingBridge
package net.mamoe.mirai.data
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.contact.checkBotPermission
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
import java.time.Instant
/**
* 表示一个群公告. [ReceiveAnnouncement] 表示
*
* 可通过 [Announcement.create] 构造.
*
* @see Announcement
*
* @since 2.7
*/
public open class Announcement internal constructor(
/**
* bot的Id
*/
public val botId: Long,
/**
* 公告的标题
*/
public val title: String,
/**
* 公告的内容
*/
public val msg: String,
/**
* 公告的可变参数. 可以通过 [AnnouncementParametersBuilder] 构建获得.
* @see AnnouncementParameters
* @see AnnouncementParametersBuilder
*/
public val parameters: AnnouncementParameters
) {
/**
* 发送该公告到群
*/
public suspend fun publish(group: Group) {
val bot = group.bot
group.checkBotPermission(MemberPermission.ADMINISTRATOR) { "Only administrator have permission to send group announcement" }
if (parameters.image == null)
Mirai.sendGroupAnnouncement(bot, group.id, covertToGroupAnnouncement())
else {
parameters.image.toExternalResource().use {
val image =
Mirai.uploadGroupAnnouncementImage(bot, group.id, it)
Mirai.sendGroupAnnouncementWithImage(bot, group.id, image, covertToGroupAnnouncement())
}
}
}
public companion object {
/**
* 构造一个 [Announcement].
* @see Announcement
*/
@JvmStatic
public fun create(botId: Long, title: String, msg: String, parameters: AnnouncementParameters): Announcement {
return Announcement(botId, title, msg, parameters)
}
}
}
/**
* 群公告的扩展参数.
*
* 可通过 [AnnouncementParametersBuilder] 构建. [AnnouncementParameters] 用于 [创建公告][Announcement.create].
*
* @since 2.7
*/
public class AnnouncementParameters internal constructor(
/**
* 群公告的图片目前仅支持发送图片不支持获得图片
*/
public val image: ByteArray? = null,
/**
* 是否发送给新成员
*/
public val sendToNewMember: Boolean = false,
/**
* 是否置顶可以有多个置顶公告
*/
public val isPinned: Boolean = false,
/**
* 是否显示能够引导群成员修改昵称的窗口
*/
public val isShowEditCard: Boolean = false,
/**
* 是否使用弹窗
*/
public val isTip: Boolean = false,
/**
* 是否需要群成员确认
*/
public val needConfirm: Boolean = false,
) {
/**
* 以该对象的参数创建一个 [AnnouncementParametersBuilder].
*/
public fun builder(): AnnouncementParametersBuilder = AnnouncementParametersBuilder().apply {
val outer = this@AnnouncementParameters
this.image = outer.image
this.sendToNewMember = outer.sendToNewMember
this.isPinned = outer.isPinned
this.isShowEditCard = outer.isShowEditCard
this.isTip = outer.isTip
this.needConfirm = outer.needConfirm
}
}
/**
* 表示一个收到的群公告. 只能由 mirai 构造.
*
* @since 2.7
*/
public class ReceiveAnnouncement internal constructor(
/**
* bot的 Id
*/
botId: Long,
/**
* 公告的标题
*/
title: String,
/**
* 公告的内容
*/
msg: String,
/**
* 公告的可变参数
*/
parameters: AnnouncementParameters,
/**
* 公告发送者的 QQ
*/
public val senderId: Long,
/**
* 公告的 `fid每个公告仅有一条 `fid`类似于主键
*/
public val fid: String,
/**
* 所有人都已阅读, 如果 [AnnouncementParameters.needConfirm] `true` 则为所有人都已确认,
*/
public val isAllRead: Boolean,
/**
* 已经阅读的成员数量如果 [AnnouncementParameters.needConfirm] `true` 则为已经确认的成员数量
*/
public val readMemberNumber: Int,
/**
* 公告发出的时间 EpochSecond ( 1970-01-01T000000Z 的秒数)
*
* @see Instant.ofEpochSecond
*/
public val publishTime: Long,
) : Announcement(botId, title, msg, parameters)
/**
* [AnnouncementParameters] 的构建器. 可以构建一个 [AnnouncementParameters] 实例.
*
* ## 获得实例
*
* 直接构造实例: `new AnnouncementParametersBuilder()` 或者从已有的公告中获取 [AnnouncementParameters.builder].
*
* ## 使用
*
* ### Kotlin 使用
*
* ```
* val parameters = buildAnnouncementParameters {
* sendToNewMember = true
* // ...
* }
* ```
*
* ### Java 使用
*
* ```java
* AnnouncementParameters parameters = new AnnouncementParametersBuilder()
* .sendToNewMember(true)
* .pinned(true)
* .build();
* ```
*
* @see buildAnnouncementParameters
*
* @since 2.7
*/
public class AnnouncementParametersBuilder @JvmOverloads constructor(
prototype: AnnouncementParameters = AnnouncementParameters()
) {
public var image: ByteArray? = prototype.image
public var sendToNewMember: Boolean = prototype.sendToNewMember
public var isPinned: Boolean = prototype.isPinned
public var isShowEditCard: Boolean = prototype.isShowEditCard
public var isTip: Boolean = prototype.isTip
public var needConfirm: Boolean = prototype.needConfirm
public fun image(image: ByteArray?): AnnouncementParametersBuilder {
this.image = image
return this
}
public fun sendToNewMember(sendToNewMember: Boolean): AnnouncementParametersBuilder {
this.sendToNewMember = sendToNewMember
return this
}
public fun pinned(isPinned: Boolean): AnnouncementParametersBuilder {
this.isPinned = isPinned
return this
}
public fun showEditCard(isShowEditCard: Boolean): AnnouncementParametersBuilder {
this.isShowEditCard = isShowEditCard
return this
}
public fun tip(isTip: Boolean): AnnouncementParametersBuilder {
this.isTip = isTip
return this
}
public fun needConfirm(needConfirm: Boolean): AnnouncementParametersBuilder {
this.needConfirm = needConfirm
return this
}
/**
* 使用当前参数构造 [AnnouncementParameters].
*/
public fun build(): AnnouncementParameters =
AnnouncementParameters(image, sendToNewMember, isPinned, isShowEditCard, isTip, needConfirm)
}
/**
* 使用 [AnnouncementParametersBuilder] 构建 [AnnouncementParameters].
* @see AnnouncementParametersBuilder
*
* @since 2.7
*/
public inline fun buildAnnouncementParameters(
builderAction: AnnouncementParametersBuilder.() -> Unit
): AnnouncementParameters = AnnouncementParametersBuilder().apply(builderAction).build()
internal fun GroupAnnouncement.covertToAnnouncement(botId: Long): ReceiveAnnouncement {
check(this.fid != null) { "GroupAnnouncement don't have id" }
check(this.settings != null) { "GroupAnnouncement don't have setting" }
return ReceiveAnnouncement(
botId = botId,
fid = fid,
senderId = sender,
publishTime = time,
title = msg.title ?: "",
msg = msg.text,
readMemberNumber = readNum,
isAllRead = isAllConfirm != 0,
parameters = buildAnnouncementParameters {
isPinned = pinned == 1
sendToNewMember = type == 20
isTip = settings.tipWindowType == 0
needConfirm = settings.confirmRequired == 1
isShowEditCard = settings.isShowEditCard == 1
}
)
}
internal fun Announcement.covertToGroupAnnouncement(): GroupAnnouncement {
return GroupAnnouncement(
sender = botId,
msg = GroupAnnouncementMsg(
title = title,
text = msg
),
type = if (parameters.sendToNewMember) 20 else 6,
settings = GroupAnnouncementSettings(
isShowEditCard = if (parameters.isShowEditCard) 1 else 0,
tipWindowType = if (parameters.isTip) 0 else 1,
confirmRequired = if (parameters.needConfirm) 1 else 0,
),
pinned = if (parameters.isPinned) 1 else 0,
)
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -26,20 +26,22 @@ public data class GroupAnnouncementList(
val ec: Int, //状态码 0 是正常的
@SerialName("em") val msg: String, //信息
val feeds: List<GroupAnnouncement>? = null, //群公告列表
val inst: List<GroupAnnouncement>? = null //置顶列表?
val inst: List<GroupAnnouncement>? = null //置顶列表? 应该是发送给新成员的
)
@MiraiExperimentalApi
@Serializable
public data class GroupAnnouncement(
@SerialName("u") val sender: Long = 0,
@SerialName("u") val sender: Long = 0, //发送者id
val msg: GroupAnnouncementMsg,
val type: Int = 0, //20 为inst , 6 为feeds
val settings: GroupAnnouncementSettings? = null,
@SerialName("pubt") val time: Long = 0,
@SerialName("read_num") val readNum: Int = 0,
@SerialName("is_read") val isRead: Int = 0,
val pinned: Int = 0,
val fid: String? = null //公告的id
@SerialName("pubt") val time: Long = 0, //发布时间
@SerialName("read_num") val readNum: Int = 0, //如果需要确认,则为确认收到的人数,反之则为已经阅读的人数
@SerialName("is_read") val isRead: Int = 0, //好像没用
@SerialName("is_all_confirm") val isAllConfirm: Int = 0, //为0 则未全部收到
val pinned: Int = 0, //1为置顶, 0为默认
val fid: String? = null, //公告的id
)
@MiraiExperimentalApi
@ -53,8 +55,16 @@ public data class GroupAnnouncementMsg(
@MiraiExperimentalApi
@Serializable
public data class GroupAnnouncementSettings(
@SerialName("is_show_edit_card") val isShowEditCard: Int = 0,
@SerialName("is_show_edit_card") val isShowEditCard: Int = 0, //引导群成员修改该昵称 1 引导
@SerialName("remind_ts") val remindTs: Int = 0,
@SerialName("tip_window_type") val tipWindowType: Int = 0,
@SerialName("confirm_required") val confirmRequired: Int = 0
@SerialName("tip_window_type") val tipWindowType: Int = 0, //是否用弹窗展示 1 不使用
@SerialName("confirm_required") val confirmRequired: Int = 0 // 是否需要确认收到 1 需要
)
@MiraiExperimentalApi
@Serializable
public data class GroupAnnouncementImage(
@SerialName("h") val height: String,
@SerialName("w") val width: String,
@SerialName("id") val id: String
)

View File

@ -14,8 +14,11 @@ import io.ktor.client.engine.okhttp.*
import io.ktor.client.features.*
import io.ktor.client.request.*
import io.ktor.client.request.forms.*
import io.ktor.http.*
import io.ktor.utils.io.core.*
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.withContext
import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes
import kotlinx.serialization.json.*
@ -56,6 +59,7 @@ import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_1
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
import kotlin.io.use
import kotlin.math.absoluteValue
import kotlin.random.Random
@ -592,6 +596,47 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
isLenient = true
}
@LowLevelApi
@MiraiExperimentalApi
override suspend fun uploadGroupAnnouncementImage(
bot: Bot,
groupId: Long,
resource: ExternalResource
): GroupAnnouncementImage = bot.asQQAndroidBot().run {
//https://youtrack.jetbrains.com/issue/KTOR-455
val rep = Mirai.Http.post<String> {
url("https://web.qun.qq.com/cgi-bin/announce/upload_img")
body = MultiPartFormDataContent(formData {
append("\"bkn\"", bkn)
append("\"source\"", "troopNotice")
append("m", "0")
append(
"\"pic_up\"",
headers = Headers.build {
append(HttpHeaders.ContentType, ContentType.Image.PNG)
append(HttpHeaders.ContentDisposition, "filename=\"temp_uploadFile.png\"")
}
) {
writeFully(resource.inputStream().withUse { readBytes() })
}
})
headers {
append(
"cookie",
" p_uin=o${id};" +
" p_skey=${client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString() ?: error("cookie parse p_skey error")}; "
)
}
}
val jsonObj = json.parseToJsonElement(rep)
if (jsonObj.jsonObject["ec"]?.jsonPrimitive?.int != 0) {
throw IllegalStateException("Upload group announcement image fail group:$groupId msg:${jsonObj.jsonObject["em"]}")
}
val id = jsonObj.jsonObject["id"]?.jsonPrimitive?.content
?: throw IllegalStateException("Upload group announcement image fail group:$groupId msg:${jsonObj.jsonObject["em"]}")
return json.decodeFromString(GroupAnnouncementImage.serializer(), id)
}
@LowLevelApi
@MiraiExperimentalApi
override suspend fun sendGroupAnnouncement(bot: Bot, groupId: Long, announcement: GroupAnnouncement): String =
@ -627,6 +672,53 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
?: throw throw IllegalStateException("Send Announcement fail group:$groupId msg:${jsonObj.jsonObject["em"]} content:${announcement.msg.text}")
}
@LowLevelApi
@MiraiExperimentalApi
override suspend fun sendGroupAnnouncementWithImage(
bot: Bot,
groupId: Long,
image: GroupAnnouncementImage,
announcement: GroupAnnouncement
): String = bot.asQQAndroidBot().run {
val rep = withContext(network.coroutineContext) {
Mirai.Http.post<String> {
url("https://web.qun.qq.com/cgi-bin/announce/add_qun_notice")
body = MultiPartFormDataContent(formData {
append("qid", groupId)
append("bkn", bkn)
append("text", announcement.msg.text)
append("pinned", announcement.pinned)
append("pic", image.id)
append("imgWidth", image.width)
append("imgHeight", image.height)
append(
"settings",
json.encodeToString(
GroupAnnouncementSettings.serializer(),
announcement.settings ?: GroupAnnouncementSettings()
)
)
append("format", "json")
})
headers {
append(
"cookie",
" p_uin=o${id};" +
" p_skey=${
client.wLoginSigInfo.psKeyMap["qun.qq.com"]?.data?.encodeToString() ?: error(
"parse error"
)
}; "
)
}
}
}
val jsonObj = json.parseToJsonElement(rep)
return jsonObj.jsonObject["new_fid"]?.jsonPrimitive?.content
?: throw throw IllegalStateException("Send Announcement with image fail group:$groupId msg:${jsonObj.jsonObject["em"]} content:${announcement.msg.text}")
}
@LowLevelApi
@MiraiExperimentalApi
override suspend fun deleteGroupAnnouncement(bot: Bot, groupId: Long, fid: String) = bot.asQQAndroidBot().run {

View File

@ -12,11 +12,11 @@
package net.mamoe.mirai.internal.contact
import kotlinx.coroutines.flow.*
import net.mamoe.mirai.LowLevelApi
import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.GroupInfo
import net.mamoe.mirai.data.MemberInfo
import net.mamoe.mirai.data.*
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.internal.QQAndroidBot
@ -248,6 +248,29 @@ internal class GroupImpl(
return result.success
}
override suspend fun getAnnouncements(): Flow<ReceiveAnnouncement> =
flow {
var i = 1
while (true) {
val result = Mirai.getRawGroupAnnouncements(bot, id, i++)
check(result.ec == 0) { "Get Group Announcement error at page $i" }
if (result.inst.isNullOrEmpty() && result.feeds.isNullOrEmpty())
return@flow
result.inst?.let { emitAll(it.asFlow()) }
result.feeds?.let { emitAll(it.asFlow()) }
}
}.map { it.covertToAnnouncement(bot.id) }
override suspend fun deleteAnnouncement(fid: String) {
checkBotPermission(MemberPermission.ADMINISTRATOR) { "Only administrator have permission to delete group announcement" }
Mirai.deleteGroupAnnouncement(bot, id, fid)
}
override suspend fun getAnnouncement(fid: String): ReceiveAnnouncement =
Mirai.getGroupAnnouncement(bot, id, fid).covertToAnnouncement(bot.id)
override fun toString(): String = "Group($id)"
}
@ -278,3 +301,4 @@ internal fun GroupImpl.newAnonymous(name: String, id: String): AnonymousMemberIm
anonymousId = id,
)
) as AnonymousMemberImpl