mirror of
https://github.com/ipnet-mesh/meshcore-hub.git
synced 2026-08-12 03:42:59 +02:00
Merge pull request #19 from ipnet-mesh/claude/research-node-id-usage-019DURYQHkvodx9sV39hTmNM
Research node ID and public key usage
This commit is contained in:
@@ -20,7 +20,7 @@ async def list_advertisements(
|
||||
_: RequireRead,
|
||||
session: DbSession,
|
||||
public_key: Optional[str] = Query(None, description="Filter by public key"),
|
||||
receiver_public_key: Optional[str] = Query(
|
||||
received_by: Optional[str] = Query(
|
||||
None, description="Filter by receiver node public key"
|
||||
),
|
||||
since: Optional[datetime] = Query(None, description="Start timestamp"),
|
||||
@@ -40,8 +40,8 @@ async def list_advertisements(
|
||||
if public_key:
|
||||
query = query.where(Advertisement.public_key == public_key)
|
||||
|
||||
if receiver_public_key:
|
||||
query = query.where(ReceiverNode.public_key == receiver_public_key)
|
||||
if received_by:
|
||||
query = query.where(ReceiverNode.public_key == received_by)
|
||||
|
||||
if since:
|
||||
query = query.where(Advertisement.received_at >= since)
|
||||
@@ -59,13 +59,13 @@ async def list_advertisements(
|
||||
# Execute
|
||||
results = session.execute(query).all()
|
||||
|
||||
# Build response with receiver_public_key
|
||||
# Build response with received_by
|
||||
items = []
|
||||
for adv, receiver_pk in results:
|
||||
data = {
|
||||
"id": adv.id,
|
||||
"receiver_node_id": adv.receiver_node_id,
|
||||
"receiver_public_key": receiver_pk,
|
||||
"received_by": receiver_pk,
|
||||
"node_id": adv.node_id,
|
||||
"public_key": adv.public_key,
|
||||
"name": adv.name,
|
||||
@@ -106,7 +106,7 @@ async def get_advertisement(
|
||||
data = {
|
||||
"id": adv.id,
|
||||
"receiver_node_id": adv.receiver_node_id,
|
||||
"receiver_public_key": receiver_pk,
|
||||
"received_by": receiver_pk,
|
||||
"node_id": adv.node_id,
|
||||
"public_key": adv.public_key,
|
||||
"name": adv.name,
|
||||
|
||||
@@ -22,7 +22,7 @@ async def list_messages(
|
||||
message_type: Optional[str] = Query(None, description="Filter by message type"),
|
||||
pubkey_prefix: Optional[str] = Query(None, description="Filter by sender prefix"),
|
||||
channel_idx: Optional[int] = Query(None, description="Filter by channel"),
|
||||
receiver_public_key: Optional[str] = Query(
|
||||
received_by: Optional[str] = Query(
|
||||
None, description="Filter by receiver node public key"
|
||||
),
|
||||
since: Optional[datetime] = Query(None, description="Start timestamp"),
|
||||
@@ -49,8 +49,8 @@ async def list_messages(
|
||||
if channel_idx is not None:
|
||||
query = query.where(Message.channel_idx == channel_idx)
|
||||
|
||||
if receiver_public_key:
|
||||
query = query.where(ReceiverNode.public_key == receiver_public_key)
|
||||
if received_by:
|
||||
query = query.where(ReceiverNode.public_key == received_by)
|
||||
|
||||
if since:
|
||||
query = query.where(Message.received_at >= since)
|
||||
@@ -96,13 +96,13 @@ async def list_messages(
|
||||
for public_key, value in session.execute(friendly_name_query).all():
|
||||
friendly_names[public_key[:12]] = value
|
||||
|
||||
# Build response with sender info and receiver_public_key
|
||||
# Build response with sender info and received_by
|
||||
items = []
|
||||
for m, receiver_pk in results:
|
||||
msg_dict = {
|
||||
"id": m.id,
|
||||
"receiver_node_id": m.receiver_node_id,
|
||||
"receiver_public_key": receiver_pk,
|
||||
"received_by": receiver_pk,
|
||||
"message_type": m.message_type,
|
||||
"pubkey_prefix": m.pubkey_prefix,
|
||||
"sender_name": (
|
||||
@@ -153,7 +153,7 @@ async def get_message(
|
||||
data = {
|
||||
"id": message.id,
|
||||
"receiver_node_id": message.receiver_node_id,
|
||||
"receiver_public_key": receiver_pk,
|
||||
"received_by": receiver_pk,
|
||||
"message_type": message.message_type,
|
||||
"pubkey_prefix": message.pubkey_prefix,
|
||||
"channel_idx": message.channel_idx,
|
||||
|
||||
@@ -20,7 +20,7 @@ async def list_telemetry(
|
||||
_: RequireRead,
|
||||
session: DbSession,
|
||||
node_public_key: Optional[str] = Query(None, description="Filter by node"),
|
||||
receiver_public_key: Optional[str] = Query(
|
||||
received_by: Optional[str] = Query(
|
||||
None, description="Filter by receiver node public key"
|
||||
),
|
||||
since: Optional[datetime] = Query(None, description="Start timestamp"),
|
||||
@@ -40,8 +40,8 @@ async def list_telemetry(
|
||||
if node_public_key:
|
||||
query = query.where(Telemetry.node_public_key == node_public_key)
|
||||
|
||||
if receiver_public_key:
|
||||
query = query.where(ReceiverNode.public_key == receiver_public_key)
|
||||
if received_by:
|
||||
query = query.where(ReceiverNode.public_key == received_by)
|
||||
|
||||
if since:
|
||||
query = query.where(Telemetry.received_at >= since)
|
||||
@@ -59,13 +59,13 @@ async def list_telemetry(
|
||||
# Execute
|
||||
results = session.execute(query).all()
|
||||
|
||||
# Build response with receiver_public_key
|
||||
# Build response with received_by
|
||||
items = []
|
||||
for tel, receiver_pk in results:
|
||||
data = {
|
||||
"id": tel.id,
|
||||
"receiver_node_id": tel.receiver_node_id,
|
||||
"receiver_public_key": receiver_pk,
|
||||
"received_by": receiver_pk,
|
||||
"node_id": tel.node_id,
|
||||
"node_public_key": tel.node_public_key,
|
||||
"parsed_data": tel.parsed_data,
|
||||
@@ -104,7 +104,7 @@ async def get_telemetry(
|
||||
data = {
|
||||
"id": tel.id,
|
||||
"receiver_node_id": tel.receiver_node_id,
|
||||
"receiver_public_key": receiver_pk,
|
||||
"received_by": receiver_pk,
|
||||
"node_id": tel.node_id,
|
||||
"node_public_key": tel.node_public_key,
|
||||
"parsed_data": tel.parsed_data,
|
||||
|
||||
@@ -19,7 +19,7 @@ router = APIRouter()
|
||||
async def list_trace_paths(
|
||||
_: RequireRead,
|
||||
session: DbSession,
|
||||
receiver_public_key: Optional[str] = Query(
|
||||
received_by: Optional[str] = Query(
|
||||
None, description="Filter by receiver node public key"
|
||||
),
|
||||
since: Optional[datetime] = Query(None, description="Start timestamp"),
|
||||
@@ -36,8 +36,8 @@ async def list_trace_paths(
|
||||
ReceiverNode, TracePath.receiver_node_id == ReceiverNode.id
|
||||
)
|
||||
|
||||
if receiver_public_key:
|
||||
query = query.where(ReceiverNode.public_key == receiver_public_key)
|
||||
if received_by:
|
||||
query = query.where(ReceiverNode.public_key == received_by)
|
||||
|
||||
if since:
|
||||
query = query.where(TracePath.received_at >= since)
|
||||
@@ -55,13 +55,13 @@ async def list_trace_paths(
|
||||
# Execute
|
||||
results = session.execute(query).all()
|
||||
|
||||
# Build response with receiver_public_key
|
||||
# Build response with received_by
|
||||
items = []
|
||||
for tp, receiver_pk in results:
|
||||
data = {
|
||||
"id": tp.id,
|
||||
"receiver_node_id": tp.receiver_node_id,
|
||||
"receiver_public_key": receiver_pk,
|
||||
"received_by": receiver_pk,
|
||||
"initiator_tag": tp.initiator_tag,
|
||||
"path_len": tp.path_len,
|
||||
"flags": tp.flags,
|
||||
@@ -104,7 +104,7 @@ async def get_trace_path(
|
||||
data = {
|
||||
"id": tp.id,
|
||||
"receiver_node_id": tp.receiver_node_id,
|
||||
"receiver_public_key": receiver_pk,
|
||||
"received_by": receiver_pk,
|
||||
"initiator_tag": tp.initiator_tag,
|
||||
"path_len": tp.path_len,
|
||||
"flags": tp.flags,
|
||||
|
||||
@@ -83,7 +83,6 @@ class MemberUpdate(BaseModel):
|
||||
class MemberRead(BaseModel):
|
||||
"""Schema for reading a member."""
|
||||
|
||||
id: str = Field(..., description="Member UUID")
|
||||
name: str = Field(..., description="Member's display name")
|
||||
callsign: Optional[str] = Field(default=None, description="Amateur radio callsign")
|
||||
role: Optional[str] = Field(default=None, description="Member's role")
|
||||
|
||||
@@ -9,11 +9,7 @@ from pydantic import BaseModel, Field
|
||||
class MessageRead(BaseModel):
|
||||
"""Schema for reading a message."""
|
||||
|
||||
id: str = Field(..., description="Message UUID")
|
||||
receiver_node_id: Optional[str] = Field(
|
||||
default=None, description="Receiving interface node UUID"
|
||||
)
|
||||
receiver_public_key: Optional[str] = Field(
|
||||
received_by: Optional[str] = Field(
|
||||
default=None, description="Receiving interface node public key"
|
||||
)
|
||||
message_type: str = Field(..., description="Message type (contact, channel)")
|
||||
@@ -85,14 +81,9 @@ class MessageFilters(BaseModel):
|
||||
class AdvertisementRead(BaseModel):
|
||||
"""Schema for reading an advertisement."""
|
||||
|
||||
id: str = Field(..., description="Advertisement UUID")
|
||||
receiver_node_id: Optional[str] = Field(
|
||||
default=None, description="Receiving interface node UUID"
|
||||
)
|
||||
receiver_public_key: Optional[str] = Field(
|
||||
received_by: Optional[str] = Field(
|
||||
default=None, description="Receiving interface node public key"
|
||||
)
|
||||
node_id: Optional[str] = Field(default=None, description="Advertised node UUID")
|
||||
public_key: str = Field(..., description="Advertised public key")
|
||||
name: Optional[str] = Field(default=None, description="Advertised name")
|
||||
adv_type: Optional[str] = Field(default=None, description="Node type")
|
||||
@@ -116,11 +107,7 @@ class AdvertisementList(BaseModel):
|
||||
class TracePathRead(BaseModel):
|
||||
"""Schema for reading a trace path."""
|
||||
|
||||
id: str = Field(..., description="Trace path UUID")
|
||||
receiver_node_id: Optional[str] = Field(
|
||||
default=None, description="Receiving interface node UUID"
|
||||
)
|
||||
receiver_public_key: Optional[str] = Field(
|
||||
received_by: Optional[str] = Field(
|
||||
default=None, description="Receiving interface node public key"
|
||||
)
|
||||
initiator_tag: int = Field(..., description="Trace identifier")
|
||||
@@ -153,14 +140,9 @@ class TracePathList(BaseModel):
|
||||
class TelemetryRead(BaseModel):
|
||||
"""Schema for reading a telemetry record."""
|
||||
|
||||
id: str = Field(..., description="Telemetry UUID")
|
||||
receiver_node_id: Optional[str] = Field(
|
||||
default=None, description="Receiving interface node UUID"
|
||||
)
|
||||
receiver_public_key: Optional[str] = Field(
|
||||
received_by: Optional[str] = Field(
|
||||
default=None, description="Receiving interface node public key"
|
||||
)
|
||||
node_id: Optional[str] = Field(default=None, description="Reporting node UUID")
|
||||
node_public_key: str = Field(..., description="Reporting node public key")
|
||||
parsed_data: Optional[dict] = Field(
|
||||
default=None, description="Decoded sensor readings"
|
||||
|
||||
@@ -41,8 +41,6 @@ class NodeTagUpdate(BaseModel):
|
||||
class NodeTagRead(BaseModel):
|
||||
"""Schema for reading a node tag."""
|
||||
|
||||
id: str = Field(..., description="Tag UUID")
|
||||
node_id: str = Field(..., description="Parent node UUID")
|
||||
key: str = Field(..., description="Tag name/key")
|
||||
value: Optional[str] = Field(default=None, description="Tag value")
|
||||
value_type: str = Field(..., description="Value type hint")
|
||||
@@ -56,7 +54,6 @@ class NodeTagRead(BaseModel):
|
||||
class NodeRead(BaseModel):
|
||||
"""Schema for reading a node."""
|
||||
|
||||
id: str = Field(..., description="Node UUID")
|
||||
public_key: str = Field(..., description="Node's 64-character hex public key")
|
||||
name: Optional[str] = Field(default=None, description="Node display name")
|
||||
adv_type: Optional[str] = Field(default=None, description="Advertisement type")
|
||||
|
||||
@@ -43,13 +43,14 @@ async def map_data(request: Request) -> JSONResponse:
|
||||
if members_response.status_code == 200:
|
||||
members_data = members_response.json()
|
||||
for member in members_data.get("items", []):
|
||||
member_info = {
|
||||
"id": member.get("id"),
|
||||
"name": member.get("name"),
|
||||
"callsign": member.get("callsign"),
|
||||
}
|
||||
members_list.append(member_info)
|
||||
# Only include members with public_key (required for node ownership)
|
||||
if member.get("public_key"):
|
||||
member_info = {
|
||||
"public_key": member.get("public_key"),
|
||||
"name": member.get("name"),
|
||||
"callsign": member.get("callsign"),
|
||||
}
|
||||
members_list.append(member_info)
|
||||
members_by_key[member["public_key"]] = member_info
|
||||
else:
|
||||
logger.warning(
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
|
||||
// Owner filter
|
||||
if (ownerFilter) {
|
||||
if (!node.owner || node.owner.id !== ownerFilter) return false;
|
||||
if (!node.owner || node.owner.public_key !== ownerFilter) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -269,12 +269,12 @@
|
||||
const ownersWithNodes = new Set();
|
||||
allNodes.forEach(node => {
|
||||
if (node.owner) {
|
||||
ownersWithNodes.add(node.owner.id);
|
||||
ownersWithNodes.add(node.owner.public_key);
|
||||
}
|
||||
});
|
||||
|
||||
// Filter members to only those who own nodes on the map
|
||||
const relevantMembers = allMembers.filter(m => ownersWithNodes.has(m.id));
|
||||
const relevantMembers = allMembers.filter(m => ownersWithNodes.has(m.public_key));
|
||||
|
||||
// Sort by name
|
||||
relevantMembers.sort((a, b) => a.name.localeCompare(b.name));
|
||||
@@ -282,7 +282,7 @@
|
||||
// Add options
|
||||
relevantMembers.forEach(member => {
|
||||
const option = document.createElement('option');
|
||||
option.value = member.id;
|
||||
option.value = member.public_key;
|
||||
option.textContent = member.callsign
|
||||
? `${member.name} (${member.callsign})`
|
||||
: member.name;
|
||||
|
||||
@@ -90,8 +90,8 @@
|
||||
{{ msg.text or '-' }}
|
||||
</td>
|
||||
<td class="text-xs">
|
||||
{% if msg.receiver_public_key %}
|
||||
<span class="font-mono" title="{{ msg.receiver_public_key }}">{{ msg.receiver_public_key[:8] }}...</span>
|
||||
{% if msg.received_by %}
|
||||
<span class="font-mono" title="{{ msg.received_by }}">{{ msg.received_by[:8] }}...</span>
|
||||
{% else %}
|
||||
<span class="opacity-50">-</span>
|
||||
{% endif %}
|
||||
|
||||
@@ -113,8 +113,8 @@
|
||||
<td>{{ adv.adv_type or '-' }}</td>
|
||||
<td>{{ adv.name or '-' }}</td>
|
||||
<td class="text-xs">
|
||||
{% if adv.receiver_public_key %}
|
||||
<span class="font-mono" title="{{ adv.receiver_public_key }}">{{ adv.receiver_public_key[:8] }}...</span>
|
||||
{% if adv.received_by %}
|
||||
<span class="font-mono" title="{{ adv.received_by }}">{{ adv.received_by[:8] }}...</span>
|
||||
{% else %}
|
||||
<span class="opacity-50">-</span>
|
||||
{% endif %}
|
||||
@@ -156,8 +156,8 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-xs">
|
||||
{% if tel.receiver_public_key %}
|
||||
<span class="font-mono" title="{{ tel.receiver_public_key }}">{{ tel.receiver_public_key[:8] }}...</span>
|
||||
{% if tel.received_by %}
|
||||
<span class="font-mono" title="{{ tel.received_by }}">{{ tel.received_by[:8] }}...</span>
|
||||
{% else %}
|
||||
<span class="opacity-50">-</span>
|
||||
{% endif %}
|
||||
|
||||
@@ -49,7 +49,6 @@ class TestGetAdvertisement:
|
||||
)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == sample_advertisement.id
|
||||
assert data["public_key"] == sample_advertisement.public_key
|
||||
|
||||
def test_get_advertisement_not_found(self, client_no_auth):
|
||||
|
||||
@@ -51,7 +51,6 @@ class TestGetMessage:
|
||||
response = client_no_auth.get(f"/api/v1/messages/{sample_message.id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == sample_message.id
|
||||
assert data["text"] == sample_message.text
|
||||
|
||||
def test_get_message_not_found(self, client_no_auth):
|
||||
|
||||
@@ -45,7 +45,6 @@ class TestGetTelemetry:
|
||||
response = client_no_auth.get(f"/api/v1/telemetry/{sample_telemetry.id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == sample_telemetry.id
|
||||
assert data["node_public_key"] == sample_telemetry.node_public_key
|
||||
|
||||
def test_get_telemetry_not_found(self, client_no_auth):
|
||||
|
||||
@@ -31,7 +31,6 @@ class TestGetTracePath:
|
||||
response = client_no_auth.get(f"/api/v1/trace-paths/{sample_trace_path.id}")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["id"] == sample_trace_path.id
|
||||
assert data["path_hashes"] == sample_trace_path.path_hashes
|
||||
|
||||
def test_get_trace_path_not_found(self, client_no_auth):
|
||||
|
||||
Reference in New Issue
Block a user