Skip to content

Commit

Permalink
feat(auth,landing): mark characters with likely expired auth tokens o…
Browse files Browse the repository at this point in the history
…n landing page and cleanup the layout a little
  • Loading branch information
updraft0 committed Nov 9, 2024
1 parent 7fdddea commit ed83616
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ case class UserCharacter(
name: String,
characterId: CharacterId,
corporationId: CorporationId,
allianceId: Option[AllianceId]
allianceId: Option[AllianceId],
authTokenFresh: Boolean
)
case class UserCharacterMap(characterId: CharacterId, mapId: MapId, mapName: String, mapRole: MapRole)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ object MapPolicy:
def allowedMapIdsForUser(userId: UserId): RIO[Env, List[(CharacterId, MapId, model.MapRole)]] =
AuthQueries.getUserCharactersById(userId).flatMap {
case None => ZIO.succeed(List.empty[(CharacterId, MapId, model.MapRole)])
case Some((_, chars)) =>
case Some((_, chars, _)) =>
allowedMapIdsForCharacters(chars.map(_.id)).map(_.toList.flatMap((k, v) => v.map(mp => (k, mp._1, mp._2))))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ import zio.*
import javax.sql.DataSource
import java.util.UUID

case class CharacterMapRole(characterId: CharacterId, mapId: MapId, role: model.MapRole)

/** Queries for user/auth related operations
*/
object AuthQueries:
import ctx.*
import auth.given
import auth.schema.*

@scala.annotation.unused // ??
private inline val ThirtyDaysInSeconds = 30 * 24 * 60

// note: this ignores session expiry
private inline def getSessionById(sessionId: UUID) =
userSession.filter(_.sessionId == lift(sessionId))
Expand All @@ -29,24 +30,22 @@ object AuthQueries:
def getCharacterByName(name: String): Result[Option[model.AuthCharacter]] =
run(quote(character.filter(_.name == lift(name)))).map(_.headOption)

def getUserCharacterByIdAndCharId(
userId: UserId,
characterId: CharacterId
): Result[Option[(model.AuthUser, model.AuthCharacter)]] =
getUserCharactersById(userId).map(_.flatMap((u, chars) => chars.find(_.id == characterId).map(c => (u -> c))))

def getUserCharactersById(
userId: UserId
): Result[Option[(model.AuthUser, List[model.AuthCharacter])]] =
): Result[Option[(model.AuthUser, List[model.AuthCharacter], List[CharacterId])]] =
run(quote {
for
user <- user.filter(_.id == lift(userId))
userCharacters <- userCharacter.join(_.userId == user.id)
characters <- character.join(_.id == userCharacters.characterId)
yield (user, characters)
authTokenCharacters <- characterAuthToken
.filter(_.updatedAt.exists(_ > unixepochMinusSeconds(ThirtyDaysInSeconds)))
.leftJoin(_.characterId == userCharacters.characterId)
.map(_.map(_.characterId))
yield (user, characters, authTokenCharacters)
}).map {
case Nil => None
case xs => Some(xs.head._1, xs.map(_._2))
case xs => Some(xs.head._1, xs.map(_._2), xs.flatMap(_._3))
}

def getUserCharactersBySessionId(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,14 @@ def getUserInfo = Endpoints.getUserInfo
.orElseFail("Failure while trying to find user")
.flatMap {
case None => ZIO.fail("No user found")
case Some(user, characters) =>
case Some(user, characters, withAuthTokens) =>
MapPolicy
.getMapsForCharacters(characters.map(_.id))
.tapErrorCause(ZIO.logWarningCause("failed map policy lookup", _))
.mapBoth(_ => "Failure while trying to find map policies", toUserInfo(user, characters, _))
.mapBoth(
_ => "Failure while trying to find map policies",
toUserInfo(user, characters, withAuthTokens, _)
)
}
)

Expand Down Expand Up @@ -87,6 +90,7 @@ def allUserEndpoints: List[ZServerEndpoint[EndpointEnv, Any]] =
private def toUserInfo(
user: model.AuthUser,
characters: List[model.AuthCharacter],
withAuthTokens: List[CharacterId],
mapsPerCharacter: Map[CharacterId, List[(model.MapModel, model.MapRole)]]
): protocol.UserInfo =
protocol.UserInfo(
Expand All @@ -97,7 +101,8 @@ private def toUserInfo(
name = ac.name,
characterId = ac.id,
corporationId = ac.corporationId,
allianceId = ac.allianceId
allianceId = ac.allianceId,
authTokenFresh = withAuthTokens.contains(ac.id)
)
},
maps = toUserCharacterMaps(mapsPerCharacter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,10 @@ object MapSession:
ctx.ourQ.offer(
protocol.MapMessage
.MapMeta(
toProtoCharacter(ctx.character),
toProtoCharacter(ctx.character, authTokenFresh = true /* lie through our teeth */ ),
toMapInfo(map),
toProtocolRole(role),
protocol.UserPreferences.Default
protocol.UserPreferences.Default /* TODO load preferences */
)
)
case _ => ZIO.logError("BUG: map not set")
Expand Down Expand Up @@ -346,12 +346,13 @@ private def toProto(msg: MapResponse): Option[protocol.MapMessage] = msg match
)
)

private def toProtoCharacter(char: model.AuthCharacter) =
private def toProtoCharacter(char: model.AuthCharacter, authTokenFresh: Boolean) =
protocol.UserCharacter(
name = char.name,
characterId = char.id,
corporationId = char.corporationId,
allianceId = char.allianceId
allianceId = char.allianceId,
authTokenFresh = authTokenFresh
)

private def toAddSystem(msg: protocol.MapRequest.AddSystem) =
Expand Down
173 changes: 124 additions & 49 deletions ui/src/main/css/views/landing-page.css
Original file line number Diff line number Diff line change
@@ -1,19 +1,66 @@
.landing-page {
$character-image-width: 132px; /* 128 + 4px margin */

& #map-selection {
margin-left: 6em;
margin-right: 6em;
display: grid;
grid-auto-columns: max-content;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr; /* TODO hmnn is this really better? */
& a.login-to-eve {
display: block;
text-align: center;
}

& table {
display: inline-block;
border-collapse: collapse;
#map-selection {
display: flex;
flex-wrap: wrap;
align-items: stretch;
}

& td.character {
& div.topnav {
height: 1.4em;
margin-bottom: 4px;
user-select: none;

/* darker look */
border: 1px solid $gray-darkest;
background-color: $gray-darkest;
border-radius: 2px;

display: flex;

padding: 0 0 0 5px;

& > * {
text-decoration: none;
align-self: center;
margin-left: 2px;
color: $gray-light;
}

/* nav buttons */
& button.navitem {
background-color: inherit;
color: $gray-lighter;
border: none;
border-radius: 2px;
font-size: 1.1em;
height: 1.2em;
width: 1.2em;

&:hover:not(:disabled) {
background: $teal-dark;
color: $orange;
}

&:disabled {
color: $gray;
}
}
}

& div.character-and-maps {
margin: 2em 3em;

flex: 0 0 calc($character-image-width * 2.5);
min-height: $character-image-width;

display: inline-flex;

& img.character-image {
display: block;
Expand All @@ -22,68 +69,96 @@
border-top-right-radius: 7px;
}

& div {
& .expired-auth {
& img.character-image, & div.character-name {
border-color: $red-dark;
}
}

& div.character-name {
max-width: $character-image-width;
background: $gray-darker;
color: $gray-lighter;
display: block;
border-bottom: 2px solid $gray;
border-left: 2px solid $gray;
border-right: 2px solid $gray;
height: 100%;
width: 100%;

border: 2px solid $gray;
border-top: none;

& button.logout {
& button {
display: inline-block;
border: none;
color: $red;
font-size: 1em;
margin-left: 2px;

&.logout {
color: $red;
&:hover {
color: $orange;
}
}
}

& a.login {
margin-left: 2px;
display: inline-block;
border: none;
font-size: 1em;
color: $green-dark;
text-decoration: none;
&:hover {
color: $orange;
color: $green;
}
}

& mark {
& mark.name {
margin-left: 2px;
background-color: inherit;
color: $gray-lighter;
text-align: center;
user-select: none;
}
}


}

& td.map-link {
& a, & button.new-map {
display: block;
height: 2em;
min-width: 6em;
max-width: 12em;
text-align: center;
border-radius: 4px;
text-decoration: none;
font-weight: bold;
font-size: 0.9em;
padding-left: 2px;
padding-right: 2px;

border: 2px solid $gray-darker;
color: $gray-lighter;
background: $teal-darkest;
& div.maps {
display: inline-flex;
flex-direction: column;
flex-wrap: wrap;
align-items: stretch;
justify-content: center;
margin-left: 1em;

& div.map-link {
margin-bottom: 0.3em;

& a, & button.new-map {
display: block;
min-height: 2em;
min-width: 6em;
text-align: left;
border-radius: 4px;
text-decoration: none;
font-weight: bold;
font-size: 0.9em;
padding-left: 2px;
padding-right: 2px;

border: 2px solid $gray-darker;
color: $gray-lighter;
background: $teal-darkest;

&:hover {
border: 2px solid $orange;
&:hover {
border: 2px solid $green-dark;
}
}
}

& button.new-map {
background: $green-dark;
color: $gray-lightest;
& button.new-map {
background: $green-dark;
color: $gray-lightest;
width: 100%;

&:hover {
border-color: $gray-lightest;
}
}
}
}


}
6 changes: 3 additions & 3 deletions ui/src/main/css/views/nav-top-view.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ div#nav-top-view {

display: flex;

padding: 0px 0px 0px 5px;
padding: 0 0 0 5px;

& > * {
align-self: center;
Expand All @@ -27,8 +27,8 @@ div#nav-top-view {
border: none;
border-radius: 2px;
font-size: 1.1em;
height: 1.3em;
width: 1em;
height: 1.2em;
width: 1.2em;

&:hover:not(:disabled) {
background: $teal-dark;
Expand Down
Loading

0 comments on commit ed83616

Please # to comment.