mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Clean a bit code and reorganize files
This commit is contained in:
parent
e942b54b56
commit
d0a241bd2d
Binary file not shown.
@ -70,6 +70,7 @@ dependencies {
|
|||||||
|
|
||||||
// Database
|
// Database
|
||||||
implementation 'com.github.Zhuinden:realm-monarchy:0.5.1'
|
implementation 'com.github.Zhuinden:realm-monarchy:0.5.1'
|
||||||
|
kapt 'dk.ilios:realmfieldnameshelper:1.1.1'
|
||||||
|
|
||||||
// Paging
|
// Paging
|
||||||
implementation "android.arch.paging:runtime:1.0.1"
|
implementation "android.arch.paging:runtime:1.0.1"
|
||||||
|
@ -8,4 +8,6 @@ open class ReadReceiptEntity(@PrimaryKey var primaryKey: String = "",
|
|||||||
var eventId: String = "",
|
var eventId: String = "",
|
||||||
var roomId: String = "",
|
var roomId: String = "",
|
||||||
var originServerTs: Double = 0.0
|
var originServerTs: Double = 0.0
|
||||||
) : RealmObject()
|
) : RealmObject() {
|
||||||
|
companion object
|
||||||
|
}
|
||||||
|
@ -2,15 +2,18 @@ package im.vector.matrix.android.internal.database.query
|
|||||||
|
|
||||||
import im.vector.matrix.android.internal.database.DBConstants
|
import im.vector.matrix.android.internal.database.DBConstants
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.ChunkEntityFields
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomEntityFields
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
import io.realm.RealmResults
|
import io.realm.RealmResults
|
||||||
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
fun ChunkEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<ChunkEntity> {
|
fun ChunkEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<ChunkEntity> {
|
||||||
return realm.where(ChunkEntity::class.java)
|
return realm.where<ChunkEntity>()
|
||||||
.equalTo("room.roomId", roomId)
|
.equalTo("${ChunkEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
|
||||||
.notEqualTo("prevToken", DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
.notEqualTo(ChunkEntityFields.PREV_TOKEN, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||||
.notEqualTo("nextToken", DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
.notEqualTo(ChunkEntityFields.NEXT_TOKEN, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ChunkEntity.Companion.findWithPrevToken(realm: Realm, roomId: String, prevToken: String?): ChunkEntity? {
|
fun ChunkEntity.Companion.findWithPrevToken(realm: Realm, roomId: String, prevToken: String?): ChunkEntity? {
|
||||||
@ -19,7 +22,7 @@ fun ChunkEntity.Companion.findWithPrevToken(realm: Realm, roomId: String, prevTo
|
|||||||
}
|
}
|
||||||
return where(realm, roomId)
|
return where(realm, roomId)
|
||||||
.and()
|
.and()
|
||||||
.equalTo("prevToken", prevToken)
|
.equalTo(ChunkEntityFields.PREV_TOKEN, prevToken)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,22 +32,22 @@ fun ChunkEntity.Companion.findWithNextToken(realm: Realm, roomId: String, nextTo
|
|||||||
}
|
}
|
||||||
return where(realm, roomId)
|
return where(realm, roomId)
|
||||||
.and()
|
.and()
|
||||||
.equalTo("nextToken", nextToken)
|
.equalTo(ChunkEntityFields.NEXT_TOKEN, nextToken)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ChunkEntity.Companion.findLastLiveChunkFromRoom(realm: Realm, roomId: String): ChunkEntity? {
|
fun ChunkEntity.Companion.findLastLiveChunkFromRoom(realm: Realm, roomId: String): ChunkEntity? {
|
||||||
return where(realm, roomId)
|
return where(realm, roomId)
|
||||||
.and()
|
.and()
|
||||||
.isNull("nextToken")
|
.isNull(ChunkEntityFields.NEXT_TOKEN)
|
||||||
.findAll()
|
.findAll()
|
||||||
.last(null)
|
.last(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List<String>): RealmResults<ChunkEntity> {
|
fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List<String>): RealmResults<ChunkEntity> {
|
||||||
return realm.where(ChunkEntity::class.java)
|
return realm.where<ChunkEntity>()
|
||||||
.`in`("events.eventId", eventIds.toTypedArray())
|
.`in`(ChunkEntityFields.EVENTS.EVENT_ID, eventIds.toTypedArray())
|
||||||
.notEqualTo("prevToken", DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
.notEqualTo(ChunkEntityFields.PREV_TOKEN, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||||
.notEqualTo("nextToken", DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
.notEqualTo(ChunkEntityFields.NEXT_TOKEN, DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||||
.findAll()
|
.findAll()
|
||||||
}
|
}
|
@ -3,49 +3,53 @@ package im.vector.matrix.android.internal.database.query
|
|||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
|
import im.vector.matrix.android.internal.database.model.ChunkEntityFields
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomEntityFields
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmList
|
import io.realm.RealmList
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
import io.realm.Sort
|
import io.realm.Sort
|
||||||
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
fun EventEntity.Companion.where(realm: Realm, eventId: String): RealmQuery<EventEntity> {
|
fun EventEntity.Companion.where(realm: Realm, eventId: String): RealmQuery<EventEntity> {
|
||||||
return realm.where(EventEntity::class.java)
|
return realm.where<EventEntity>()
|
||||||
.equalTo("eventId", eventId)
|
.equalTo(EventEntityFields.EVENT_ID, eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun EventEntity.Companion.where(realm: Realm, roomId: String, type: String? = null): RealmQuery<EventEntity> {
|
fun EventEntity.Companion.where(realm: Realm, roomId: String, type: String? = null): RealmQuery<EventEntity> {
|
||||||
val query = realm.where(EventEntity::class.java)
|
val query = realm.where<EventEntity>()
|
||||||
.equalTo("chunk.room.roomId", roomId)
|
.equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
query.equalTo("type", type)
|
query.equalTo(EventEntityFields.TYPE, type)
|
||||||
}
|
}
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
fun EventEntity.Companion.stateEvents(realm: Realm, roomId: String): RealmQuery<EventEntity> {
|
fun EventEntity.Companion.stateEvents(realm: Realm, roomId: String): RealmQuery<EventEntity> {
|
||||||
return realm.where(EventEntity::class.java)
|
return realm.where<EventEntity>()
|
||||||
.equalTo("chunk.room.roomId", roomId)
|
.equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.ROOM}.${RoomEntityFields.ROOM_ID}", roomId)
|
||||||
.isNotNull("stateKey")
|
.isNotNull(EventEntityFields.STATE_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RealmQuery<EventEntity>.last(from: Long? = null): EventEntity? {
|
fun RealmQuery<EventEntity>.last(from: Long? = null): EventEntity? {
|
||||||
if (from != null) {
|
if (from != null) {
|
||||||
this.lessThanOrEqualTo("originServerTs", from)
|
this.lessThanOrEqualTo(EventEntityFields.ORIGIN_SERVER_TS, from)
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
.sort("originServerTs", Sort.DESCENDING)
|
.sort(EventEntityFields.ORIGIN_SERVER_TS, Sort.DESCENDING)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RealmList<EventEntity>.fastContains(eventEntity: EventEntity): Boolean {
|
fun RealmList<EventEntity>.fastContains(eventEntity: EventEntity): Boolean {
|
||||||
return this.where().equalTo("eventId", eventEntity.eventId).findFirst() != null
|
return this.where().equalTo(EventEntityFields.EVENT_ID, eventEntity.eventId).findFirst() != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun EventEntity.Companion.findAllRoomMembers(realm: Realm, roomId: String): Map<String, RoomMember> {
|
fun EventEntity.Companion.findAllRoomMembers(realm: Realm, roomId: String): Map<String, RoomMember> {
|
||||||
return EventEntity
|
return EventEntity
|
||||||
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
||||||
.sort("originServerTs")
|
.sort(EventEntityFields.ORIGIN_SERVER_TS)
|
||||||
.findAll()
|
.findAll()
|
||||||
.map { it.asDomain() }
|
.map { it.asDomain() }
|
||||||
.associateBy { it.stateKey!! }
|
.associateBy { it.stateKey!! }
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
package im.vector.matrix.android.internal.database.query
|
||||||
|
|
||||||
|
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.ReadReceiptEntityFields
|
||||||
|
import io.realm.Realm
|
||||||
|
import io.realm.RealmQuery
|
||||||
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
|
fun ReadReceiptEntity.Companion.where(realm: Realm, roomId: String, userId: String): RealmQuery<ReadReceiptEntity> {
|
||||||
|
return realm.where<ReadReceiptEntity>()
|
||||||
|
.equalTo(ReadReceiptEntityFields.ROOM_ID, roomId)
|
||||||
|
.equalTo(ReadReceiptEntityFields.USER_ID, userId)
|
||||||
|
}
|
@ -2,17 +2,19 @@ package im.vector.matrix.android.internal.database.query
|
|||||||
|
|
||||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomEntityFields
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
fun RoomEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<RoomEntity> {
|
fun RoomEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<RoomEntity> {
|
||||||
return realm.where<RoomEntity>(RoomEntity::class.java).equalTo("roomId", roomId)
|
return realm.where<RoomEntity>().equalTo(RoomEntityFields.ROOM_ID, roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RoomEntity.Companion.where(realm: Realm, membership: MyMembership? = null): RealmQuery<RoomEntity> {
|
fun RoomEntity.Companion.where(realm: Realm, membership: MyMembership? = null): RealmQuery<RoomEntity> {
|
||||||
val query = realm.where(RoomEntity::class.java)
|
val query = realm.where<RoomEntity>()
|
||||||
if (membership != null) {
|
if (membership != null) {
|
||||||
query.equalTo("membership", membership.name)
|
query.equalTo(RoomEntityFields.MEMBERSHIP_STR, membership.name)
|
||||||
}
|
}
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package im.vector.matrix.android.internal.database.query
|
package im.vector.matrix.android.internal.database.query
|
||||||
|
|
||||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery<RoomSummaryEntity> {
|
fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery<RoomSummaryEntity> {
|
||||||
val query = realm.where(RoomSummaryEntity::class.java)
|
val query = realm.where<RoomSummaryEntity>()
|
||||||
if (roomId != null) {
|
if (roomId != null) {
|
||||||
query.equalTo("roomId", roomId)
|
query.equalTo(RoomSummaryEntityFields.ROOM_ID, roomId)
|
||||||
}
|
}
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
|||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||||
import im.vector.matrix.android.internal.database.query.last
|
import im.vector.matrix.android.internal.database.query.last
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ class MessageEventInterceptor(val monarchy: Monarchy) : EnrichedEventInterceptor
|
|||||||
monarchy.doWithRealm { realm ->
|
monarchy.doWithRealm { realm ->
|
||||||
val roomMember = EventEntity
|
val roomMember = EventEntity
|
||||||
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
||||||
.equalTo("stateKey", event.root.sender)
|
.equalTo(EventEntityFields.STATE_KEY, event.root.sender)
|
||||||
.last(from = event.root.originServerTs)
|
.last(from = event.root.originServerTs)
|
||||||
?.asDomain()
|
?.asDomain()
|
||||||
event.enrichWith(roomMember)
|
event.enrichWith(roomMember)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package im.vector.matrix.android.internal.session.room
|
package im.vector.matrix.android.internal.session.room
|
||||||
|
|
||||||
import im.vector.matrix.android.internal.network.NetworkConstants
|
import im.vector.matrix.android.internal.network.NetworkConstants
|
||||||
import im.vector.matrix.android.internal.session.room.model.RoomMembersResponse
|
import im.vector.matrix.android.internal.session.room.members.RoomMembersResponse
|
||||||
import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEvent
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
@ -14,7 +14,6 @@ import im.vector.matrix.android.internal.database.query.findAllRoomMembers
|
|||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
import im.vector.matrix.android.internal.session.room.model.RoomMembersResponse
|
|
||||||
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
||||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package im.vector.matrix.android.internal.session.room.model
|
package im.vector.matrix.android.internal.session.room.members
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
@ -9,6 +9,7 @@ import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
|||||||
import im.vector.matrix.android.api.session.room.TimelineHolder
|
import im.vector.matrix.android.api.session.room.TimelineHolder
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.session.events.interceptor.MessageEventInterceptor
|
import im.vector.matrix.android.internal.session.events.interceptor.MessageEventInterceptor
|
||||||
import io.realm.Sort
|
import io.realm.Sort
|
||||||
@ -30,7 +31,7 @@ class DefaultTimelineHolder(private val roomId: String,
|
|||||||
.findAll()
|
.findAll()
|
||||||
.last(null)
|
.last(null)
|
||||||
?.let {
|
?.let {
|
||||||
it.events.where().sort("originServerTs", Sort.DESCENDING)
|
it.events.where().sort(EventEntityFields.ORIGIN_SERVER_TS, Sort.DESCENDING)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val domainSourceFactory = realmDataSourceFactory
|
val domainSourceFactory = realmDataSourceFactory
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package im.vector.matrix.android.internal.session.room.model
|
package im.vector.matrix.android.internal.session.room.timeline
|
||||||
|
|
||||||
enum class PaginationDirection(val value: String) {
|
enum class PaginationDirection(val value: String) {
|
||||||
/**
|
/**
|
@ -18,8 +18,6 @@ import im.vector.matrix.android.internal.database.query.where
|
|||||||
import im.vector.matrix.android.internal.legacy.util.FilterUtil
|
import im.vector.matrix.android.internal.legacy.util.FilterUtil
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
import im.vector.matrix.android.internal.session.room.model.PaginationDirection
|
|
||||||
import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
|
||||||
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
||||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||||
|
@ -7,8 +7,6 @@ import im.vector.matrix.android.api.failure.Failure
|
|||||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
|
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
|
||||||
import im.vector.matrix.android.internal.session.room.model.PaginationDirection
|
|
||||||
import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
|
||||||
import im.vector.matrix.android.internal.util.PagingRequestHelper
|
import im.vector.matrix.android.internal.util.PagingRequestHelper
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package im.vector.matrix.android.internal.session.room.model
|
package im.vector.matrix.android.internal.session.room.timeline
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
Loading…
Reference in New Issue
Block a user