require('dotenv').config();
const express = require('express');
const multer = require('multer');
const axios = require('axios');
const AWS = require('aws-sdk');
const fs = require('fs');
const path = require('path');
const app = express();
const upload = multer({ dest: 'uploads/' });
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION,
});
const s3 = new AWS.S3();
const LINEAR_API_URL = 'https://api.linear.app/graphql';
async function uploadFileToS3(file) {
const fileContent = fs.readFileSync(file.path);
const uploadParams = {
Bucket: process.env.S3_BUCKET_NAME,
Key: `linear_issues/${Date.now()}_${file.originalname}`,
Body: fileContent,
ContentType: file.mimetype,
};
const result = await s3.upload(uploadParams).promise();
// Remove file from local storage
fs.unlinkSync(file.path);
return result.Location; // public S3 URL
}
async function createLinearIssue(title, description) {
const query = `
mutation {
issueCreate(
input: {
teamId: "${process.env.LINEAR_TEAM_ID}",
title: "${title}",
description: "${description}"
}
) {
success
issue {
id
identifier
url
}
}
}
`;
const response = await axios.post(
LINEAR_API_URL,
{ query },
{
headers: {
Authorization: `Bearer ${process.env.LINEAR_API_KEY}`,
'Content-Type': 'application/json',
},
}
);
return response.data.data.issueCreate.issue.url;
}
app.post('/report', upload.single('file'), async (req, res) => {
try {
const { title, description } = req.body;
const file = req.file;
let fileUrl = 'No file uploaded';
if (file) {
fileUrl = await uploadFileToS3(file);
}
const issueDescription = `${description}\n\nAttached file: ${fileUrl}`;
const issueUrl = await createLinearIssue(title, issueDescription);
res.status(200).json({ success: true, issueUrl });
} catch (error) {
console.error('Error:', error.message);
res.status(500).json({ success: false, error: error.message });
}
});
app.listen(process.env.PORT, () => {
console.log(`Server running at http://localhost:${process.env.PORT}`);
});