Browse Source

Initial commit

master
Sven Slootweg 2 years ago
commit
579ab4ccb7
  1. 1
      .gitignore
  2. 78
      index.js
  3. 23
      package.json
  4. 25
      public/style.css
  5. 13
      views/error.jsx
  6. 25
      views/index.jsx
  7. 24
      views/layout.jsx
  8. 40
      views/rooms.jsx
  9. 3474
      yarn.lock

1
.gitignore

@ -0,0 +1 @@
node_modules

78
index.js

@ -0,0 +1,78 @@
"use strict";
const Promise = require("bluebird");
const express = require("express");
const expressPromiseRouter = require("express-promise-router");
const expressReactViews = require("@joepie91/express-react-views");
const path = require("path");
const url = require("url");
const autodiscoverClientConfiguration = require("@modular-matrix/autodiscover-client-configuration");
const bhttp = require("bhttp");
const createError = require("create-error");
let UpstreamError = createError("UpstreamError");
function generateSince(hostname, token) {
return url.format({ pathname: "/show-rooms", query: {
hostname: hostname,
since: token
} });
}
let app = express();
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jsx");
app.engine("jsx", expressReactViews.createEngine());
app.use(express.static(path.join(__dirname, "public")));
let router = expressPromiseRouter();
router.get("/", (req, res) => {
res.render("index");
});
router.get("/show-rooms", (req, res) => {
return Promise.try(() => {
return autodiscoverClientConfiguration.discover(req.query.hostname);
}).then((clientConfiguration) => {
let roomsUrl = url.format({
... url.parse(clientConfiguration.homeserver),
pathname: "/_matrix/client/r0/publicRooms",
query: { since: req.query.since }
});
return Promise.try(() => {
return bhttp.get(roomsUrl);
}).then((response) => {
if (response.statusCode === 200) {
console.log(response.body);
// next_batch
res.render("rooms", {
rooms: response.body.chunk,
nextBatchUrl: (response.body.next_batch != null)
? generateSince(req.query.hostname, response.body.next_batch)
: null,
previousBatchUrl: (response.body.previous_batch != null)
? generateSince(req.query.hostname, response.body.previous_batch)
: null,
});
} else {
throw new UpstreamError(`Non-200 status code received from homeserver: ${response.statusCode}`);
}
});
});
});
app.use(router);
app.use((error, req, res, next) => {
if (error instanceof UpstreamError || error instanceof autodiscoverClientConfiguration.LookupFailed) {
res.render("error", { error: error });
} else {
throw error;
}
});
app.listen(3000);

23
package.json

@ -0,0 +1,23 @@
{
"name": "matrix-room-list-viewer",
"description": "A simple tool for viewing the list of public rooms on a given Matrix server",
"version": "1.0.0",
"main": "index.js",
"repository": "git@git.cryto.net:joepie91/matrix-room-list-viewer.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"@joepie91/express-react-views": "^1.0.1",
"@modular-matrix/autodiscover-client-configuration": "^1.0.0",
"bhttp": "^1.2.4",
"bluebird": "^3.5.5",
"create-error": "^0.3.1",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
"react": "^16.9.0",
"react-dom": "^16.9.0"
},
"devDependencies": {
"nodemon": "^1.19.1"
}
}

25
public/style.css

@ -0,0 +1,25 @@
body {
font-family: sans-serif;
}
.container {
max-width: 960px;
margin: 0 auto;
}
.room {
margin: 1em 0;
}
.room .name, .room .alias, .room .userCount {
display: inline-block;
margin-right: 1em;
}
.room .name {
font-weight: bold;
}
.room .alias {
color: rgb(58, 58, 58);
}

13
views/error.jsx

@ -0,0 +1,13 @@
"use strict";
const React = require("react");
const Layout = require("./layout");
module.exports = function Error({ error }) {
return (
<Layout>
{error.message}
</Layout>
);
};

25
views/index.jsx

@ -0,0 +1,25 @@
"use strict";
const React = require("react");
const Layout = require("./layout");
function Field({ id, type, name, label, children }) {
return (
<div className="formField">
<label htmlFor={`field_${id}`}>{label}</label>&nbsp;
<input type={type} name={name} id={`field_${id}`} />
</div>
);
}
module.exports = function Index() {
return (
<Layout>
<form method="get" action="/show-rooms">
<Field label="Homeserver" type="text" name="hostname" id="homeserver" />
<button type="submit">Show rooms</button>
</form>
</Layout>
);
};

24
views/layout.jsx

@ -0,0 +1,24 @@
"use strict";
const React = require("react");
module.exports = function Layout({ children }) {
return (
<html lang="en">
<head>
<meta charSet="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta httpEquiv="X-UA-Compatible" content="ie=edge"/>
<link rel="stylesheet" href="/style.css"/>
<title>Matrix Room List Viewer</title>
</head>
<body>
<div className="container">
<h1>Matrix Room List Viewer</h1>
<hr/>
{children}
</div>
</body>
</html>
);
};

40
views/rooms.jsx

@ -0,0 +1,40 @@
"use strict";
const React = require("react");
const Layout = require("./layout");
function Room({ room }) {
return (
<div className="room">
<div className="name">{room.name}</div>
<div className="userCount">{room.num_joined_members} users</div>
<div className="alias">{room.canonical_alias}</div>
<div className="topic">{room.topic}</div>
</div>
);
}
module.exports = function Rooms({ rooms, nextBatchUrl, previousBatchUrl }) {
return (
<Layout>
<div className="navigation">
{(previousBatchUrl != null)
? <a href={previousBatchUrl}>&lt;&lt; Previous</a>
: null
}
{(previousBatchUrl != null && nextBatchUrl != null)
? " | "
: null
}
{(nextBatchUrl != null)
? <a href={nextBatchUrl}>Next &gt;&gt;</a>
: null
}
</div>
{rooms.map((room) => {
return <Room key={room.id} room={room} />;
})}
</Layout>
);
};

3474
yarn.lock
File diff suppressed because it is too large
View File

Loading…
Cancel
Save