Kick off conflicting usernames + Frontend mobile fixes
* When JWT tokens are used to join the chat and the username conflicts: instead of renaming the new user to add a "2" it will disconnect the original login (sending a message that they have signed in somewhere else and are logged out now) * When disconnected the text entry box will be greyed out. * Improvements for the mobile user experience: if you're viewing the chat history panel and have unread messages or DMs, a number indicator appears on the channels button. It is grey for public channel messages or red if any of them are DMs * Fix the emoji picker drop-down on the first messages of a DM thread
This commit is contained in:
parent
6724792ba0
commit
75c7511410
|
@ -51,7 +51,25 @@ func (s *Server) OnLogin(sub *Subscriber, msg Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the username is unique, or rename it.
|
// Ensure the username is unique, or rename it.
|
||||||
msg.Username = s.UniqueUsername(msg.Username)
|
username, err := s.UniqueUsername(msg.Username)
|
||||||
|
if err != nil {
|
||||||
|
// If JWT authentication was used: disconnect the original (conflicting) username.
|
||||||
|
if claims.Subject == msg.Username {
|
||||||
|
if other, err := s.GetSubscriber(msg.Username); err == nil {
|
||||||
|
other.ChatServer("You have been signed out of chat because you logged in from another location.")
|
||||||
|
other.SendJSON(Message{
|
||||||
|
Action: ActionKick,
|
||||||
|
})
|
||||||
|
s.DeleteSubscriber(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
// They will take over their original username.
|
||||||
|
username = msg.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
// If JWT auth was not used: UniqueUsername already gave them a uniquely spelled name.
|
||||||
|
}
|
||||||
|
msg.Username = username
|
||||||
|
|
||||||
// Use their username.
|
// Use their username.
|
||||||
sub.Username = msg.Username
|
sub.Username = msg.Username
|
||||||
|
|
|
@ -275,8 +275,8 @@ func (s *Server) IterSubscribers(isLocked ...bool) []*Subscriber {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// UniqueUsername ensures a username will be unique or renames it.
|
// UniqueUsername ensures a username will be unique or renames it. If the name is already unique, the error result is nil.
|
||||||
func (s *Server) UniqueUsername(username string) string {
|
func (s *Server) UniqueUsername(username string) (string, error) {
|
||||||
var (
|
var (
|
||||||
subs = s.IterSubscribers()
|
subs = s.IterSubscribers()
|
||||||
usernames = map[string]interface{}{}
|
usernames = map[string]interface{}{}
|
||||||
|
@ -297,7 +297,11 @@ func (s *Server) UniqueUsername(username string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return username
|
if username != origUsername {
|
||||||
|
return username, errors.New("username was not unique and a unique name has been returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
return username, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast a message to the chat room.
|
// Broadcast a message to the chat room.
|
||||||
|
|
|
@ -975,6 +975,23 @@ const app = Vue.createApp({
|
||||||
}
|
}
|
||||||
return this.channels[channel].unread;
|
return this.channels[channel].unread;
|
||||||
},
|
},
|
||||||
|
hasAnyUnread() {
|
||||||
|
// Returns total unread count (for mobile responsive view to show in the left drawer button)
|
||||||
|
let count = 0;
|
||||||
|
for (let channel of Object.keys(this.channels)) {
|
||||||
|
count += this.channels[channel].unread;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
anyUnreadDMs() {
|
||||||
|
// Returns true if any unread messages are DM threads
|
||||||
|
for (let channel of Object.keys(this.channels)) {
|
||||||
|
if (channel.indexOf("@") === 0 && this.channels[channel].unread > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
openDMs(user) {
|
openDMs(user) {
|
||||||
let channel = "@" + user.username;
|
let channel = "@" + user.username;
|
||||||
this.initHistory(channel);
|
this.initHistory(channel);
|
||||||
|
|
|
@ -503,7 +503,7 @@
|
||||||
<div class="columns is-mobile card-header-title has-text-light">
|
<div class="columns is-mobile card-header-title has-text-light">
|
||||||
<div class="column is-narrow mobile-only">
|
<div class="column is-narrow mobile-only">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="button is-success"
|
class="button is-success px-2"
|
||||||
@click="openChatPanel">
|
@click="openChatPanel">
|
||||||
<i class="fa fa-arrow-left"></i>
|
<i class="fa fa-arrow-left"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -525,7 +525,7 @@
|
||||||
:class="{'is-active': c.ID == channel}">
|
:class="{'is-active': c.ID == channel}">
|
||||||
[[c.Name]]
|
[[c.Name]]
|
||||||
<span v-if="hasUnread(c.ID)"
|
<span v-if="hasUnread(c.ID)"
|
||||||
class="tag is-danger">
|
class="tag">
|
||||||
[[hasUnread(c.ID)]]
|
[[hasUnread(c.ID)]]
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -581,11 +581,16 @@
|
||||||
<div class="column is-narrow mobile-only pr-0">
|
<div class="column is-narrow mobile-only pr-0">
|
||||||
<!-- Responsive mobile button to pan to Left Column -->
|
<!-- Responsive mobile button to pan to Left Column -->
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="button is-success"
|
class="button is-success px-2"
|
||||||
:class="{'is-small': isDM}"
|
|
||||||
@click="openChannelsPanel">
|
@click="openChannelsPanel">
|
||||||
<i v-if="isDM" class="fa fa-arrow-left"></i>
|
<i v-if="isDM" class="fa fa-arrow-left"></i>
|
||||||
<i v-else class="fa fa-message"></i>
|
<i v-else class="fa fa-comments"></i>
|
||||||
|
|
||||||
|
<!-- Indicator badge for unread messages -->
|
||||||
|
<span v-if="hasAnyUnread() > 0"
|
||||||
|
class="tag ml-1" :class="{'is-danger': anyUnreadDMs()}">
|
||||||
|
[[hasAnyUnread()]]
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
|
@ -613,7 +618,7 @@
|
||||||
<div v-if="!isDM" class="column is-narrow mobile-only">
|
<div v-if="!isDM" class="column is-narrow mobile-only">
|
||||||
<!-- Responsive mobile button to pan to Right Column -->
|
<!-- Responsive mobile button to pan to Right Column -->
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="button is-success"
|
class="button is-success px-2"
|
||||||
@click="openWhoPanel">
|
@click="openWhoPanel">
|
||||||
<i class="fa fa-user-group"></i>
|
<i class="fa fa-user-group"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -881,7 +886,9 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Emoji reactions menu -->
|
<!-- Emoji reactions menu -->
|
||||||
<div v-if="msg.msgID" class="dropdown is-up is-right emoji-button" onclick="this.classList.toggle('is-active')">
|
<div v-if="msg.msgID" class="dropdown is-right emoji-button"
|
||||||
|
:class="{'is-up': i >= 2}"
|
||||||
|
onclick="this.classList.toggle('is-active')">
|
||||||
<div class="dropdown-trigger">
|
<div class="dropdown-trigger">
|
||||||
<button class="button is-small px-2" aria-haspopup="true" :aria-controls="`react-menu-${msg.msgID}`">
|
<button class="button is-small px-2" aria-haspopup="true" :aria-controls="`react-menu-${msg.msgID}`">
|
||||||
<span>
|
<span>
|
||||||
|
@ -956,7 +963,8 @@
|
||||||
<input type="text" class="input"
|
<input type="text" class="input"
|
||||||
v-model="message"
|
v-model="message"
|
||||||
placeholder="Message"
|
placeholder="Message"
|
||||||
@keydown="sendTypingNotification()">
|
@keydown="sendTypingNotification()"
|
||||||
|
:disabled="!ws.connected">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="column pl-1 is-narrow">
|
<div class="column pl-1 is-narrow">
|
||||||
|
@ -979,7 +987,7 @@
|
||||||
<div class="column">Who Is Online</div>
|
<div class="column">Who Is Online</div>
|
||||||
<div class="column is-narrow mobile-only">
|
<div class="column is-narrow mobile-only">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="button is-success"
|
class="button is-success px-2"
|
||||||
@click="openChatPanel">
|
@click="openChatPanel">
|
||||||
<i class="fa fa-arrow-left"></i>
|
<i class="fa fa-arrow-left"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user