64 lines
2.2 KiB
Dart
64 lines
2.2 KiB
Dart
import '../../core/data/backend.dart';
|
|
import 'station_data.dart';
|
|
|
|
/// STATION 허브의 실 서버 구현 — S-S-HUB.
|
|
///
|
|
/// `stationLinks` 는 운영만 쓰고 로그인 사용자는 읽기만 한다(보안 규칙 §7).
|
|
/// 정렬은 팬덤별 `rank` 오름차순이며, 이 순서가 곧 운영이 정한 노출 순서다.
|
|
/// 앱에서 다시 정렬하지 않는다 — 그러면 운영 화면과 앱이 다르게 보인다.
|
|
class FirestoreStationRepository implements StationRepository {
|
|
FirestoreStationRepository(this._backend);
|
|
|
|
final Backend _backend;
|
|
|
|
/// 소속 팬덤. 라우터가 모르는 값이라 사용자 문서에서 한 번 읽어 들고 있는다.
|
|
String? _fandomId;
|
|
|
|
@override
|
|
Future<StationSnapshot> load() async {
|
|
final cached = _fandomId;
|
|
final String id;
|
|
if (cached != null) {
|
|
id = cached;
|
|
} else {
|
|
final snap = await _backend.db.doc('users/${_backend.requireUid}').get();
|
|
id = _fandomId = (snap.data() ?? const {}).strOr('fandomId');
|
|
}
|
|
// 팬덤이 없으면 큐레이션 대상이 정해지지 않는다. 빈 상태로 두고 화면이 안내한다.
|
|
if (id.isEmpty) {
|
|
return const StationSnapshot(links: [], canSuggest: false);
|
|
}
|
|
|
|
final snap = await _backend.db
|
|
.collection('stationLinks')
|
|
.where('fandomId', isEqualTo: id)
|
|
.orderBy('rank')
|
|
.limit(30)
|
|
.get();
|
|
|
|
return StationSnapshot(
|
|
links: [
|
|
for (final doc in snap.docs)
|
|
StationLink(
|
|
id: doc.id,
|
|
title: doc.data().strOr('title'),
|
|
url: doc.data().strOr('url'),
|
|
category: _category(doc.data().strOr('category')),
|
|
description: doc.data().strOr('description'),
|
|
verified: doc.data()['verified'] == true,
|
|
),
|
|
],
|
|
canSuggest: _backend.uid != null,
|
|
);
|
|
}
|
|
|
|
/// 모르는 값은 「공식」으로 떨어뜨리지 않고 판매처로 본다 — 공식 배지를
|
|
/// 검증하지 않은 링크에 붙이는 쪽이 더 위험하다.
|
|
StationCategory _category(String raw) => switch (raw) {
|
|
'official' => StationCategory.official,
|
|
'ticket' => StationCategory.ticket,
|
|
'media' => StationCategory.media,
|
|
_ => StationCategory.shop,
|
|
};
|
|
}
|