Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions gurubu-backend/controllers/storyPointEstimationController.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ exports.estimateStoryPoint = async (req, res) => {
try {
const { boardName, issueSummary, issueDescription, threadId } = req.body;

if(!boardName) {
return res.status(400).json({ error: "Board name is required" });
if (!boardName) {
return res.status(400).json({ error: "Board name is required" });
}

if (!issueSummary) {
Expand All @@ -15,9 +15,12 @@ exports.estimateStoryPoint = async (req, res) => {
if (!issueDescription) {
return res.status(400).json({ error: "Issue Description is required" });
}

const assistantId = process.env.OPENAI_ASSISTANT_ID;

if (!assistantId) {
return res.status(500).json({ error: "OpenAI Assistant ID not configured" });
}

const message = createStoryPointPrompt(issueSummary, issueDescription);

const response = await openaiService.askAssistant(assistantId, message, threadId);
Expand Down
34 changes: 31 additions & 3 deletions gurubu-backend/services/jiraInitialStoryPointService.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,38 @@ class JiraInitialStoryPointService {
storyPointFieldName;

constructor() {
this.baseUrl = process.env.JIRA_BASE_URL || "";
// Validate required environment variables
const requiredEnvVars = {
JIRA_BASE_URL: process.env.JIRA_BASE_URL,
JIRA_USERNAME: process.env.JIRA_USERNAME,
JIRA_API_TOKEN: process.env.JIRA_API_TOKEN,
JIRA_PROJECT_KEY_FOUR: process.env.JIRA_PROJECT_KEY_FOUR
};

const missingVars = [];
for (const [key, value] of Object.entries(requiredEnvVars)) {
if (!value || value.trim() === '') {
missingVars.push(key);
}
}

if (missingVars.length > 0) {
throw new Error(
`Missing required environment variables for JIRA service: ${missingVars.join(', ')}. ` +
'Please check your .env file and ensure all JIRA configuration variables are set.'
);
}

// Validate JIRA_BASE_URL format
try {
new URL(this.baseUrl = process.env.JIRA_BASE_URL);
} catch (error) {
throw new Error(`Invalid JIRA_BASE_URL format: ${process.env.JIRA_BASE_URL}. Must be a valid URL.`);
}

this.auth = {
username: process.env.JIRA_USERNAME || "",
password: process.env.JIRA_API_TOKEN || "",
username: process.env.JIRA_USERNAME,
password: process.env.JIRA_API_TOKEN,
};
this.storyPointFieldName = process.env.JIRA_PROJECT_KEY_FOUR;
}
Expand Down
62 changes: 50 additions & 12 deletions gurubu-backend/services/jiraService.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,49 @@ class JiraService {
auth;

constructor() {
this.baseUrl = process.env.JIRA_BASE_URL || "";
// Validate required environment variables
const requiredEnvVars = {
JIRA_BASE_URL: process.env.JIRA_BASE_URL,
JIRA_USERNAME: process.env.JIRA_USERNAME,
JIRA_API_TOKEN: process.env.JIRA_API_TOKEN
};

const missingVars = [];
for (const [key, value] of Object.entries(requiredEnvVars)) {
if (!value || value.trim() === '') {
missingVars.push(key);
}
}

if (missingVars.length > 0) {
throw new Error(
`Missing required environment variables for JIRA service: ${missingVars.join(', ')}. ` +
'Please check your .env file and ensure all JIRA configuration variables are set.'
);
}

// Validate JIRA_BASE_URL format
try {
new URL(this.baseUrl = process.env.JIRA_BASE_URL);
} catch (error) {
throw new Error(`Invalid JIRA_BASE_URL format: ${process.env.JIRA_BASE_URL}. Must be a valid URL.`);
}

this.auth = {
username: process.env.JIRA_USERNAME || "",
password: process.env.JIRA_API_TOKEN || "",
username: process.env.JIRA_USERNAME,
password: process.env.JIRA_API_TOKEN,
};

// Warn about optional JIRA project keys if not set
const optionalKeys = ['JIRA_PROJECT_KEY_ONE', 'JIRA_PROJECT_KEY_TWO', 'JIRA_PROJECT_KEY_THREE', 'JIRA_PROJECT_KEY_FOUR'];
const missingOptionalKeys = optionalKeys.filter(key => !process.env[key]);

if (missingOptionalKeys.length > 0) {
console.warn(
`Warning: Optional JIRA project keys not configured: ${missingOptionalKeys.join(', ')}. ` +
'Some features may not work correctly without these configurations.'
);
}
}

mapIssueResponse(response) {
Expand Down Expand Up @@ -47,14 +85,14 @@ class JiraService {
key: issue.key,
assignee: issue.fields.assignee
? {
self: `${this.baseUrl}/rest/api/2/user?username=${issue.fields.assignee.name}`,
name: issue.fields.assignee.name,
key: `JIRAUSER_${issue.fields.assignee.name}`,
emailAddress: issue.fields.assignee.emailAddress,
displayName: issue.fields.assignee.displayName,
active: true,
timeZone: "Europe/Istanbul",
}
self: `${this.baseUrl}/rest/api/2/user?username=${issue.fields.assignee.name}`,
name: issue.fields.assignee.name,
key: `JIRAUSER_${issue.fields.assignee.name}`,
emailAddress: issue.fields.assignee.emailAddress,
displayName: issue.fields.assignee.displayName,
active: true,
timeZone: "Europe/Istanbul",
}
: null,
pairAssignee,
testAssignee,
Expand Down Expand Up @@ -298,7 +336,7 @@ class JiraService {
baseClauses.push("statusCategory != Done");
}
const jql = `${baseClauses.join(" AND ")} ORDER BY updated DESC`;

const response = await axios.get(`${this.baseUrl}/rest/api/2/search`, {
params: {
jql,
Expand Down
7 changes: 5 additions & 2 deletions gurubu-backend/services/openaiService.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ dotenv.config();

class OpenAIService {
constructor() {
if (!process.env.OPENAI_API_KEY) {
throw new Error('OPENAI_API_KEY environment variable is required');
}
Comment on lines +8 to +10

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In cases where there is no API, we should not interrupt the application with a throw; we can discuss a better approach, such as a catch scenario and a user-friendly flow.

this.openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
Expand All @@ -13,7 +16,7 @@ class OpenAIService {

async askAssistant(assistantId, message, threadId = null) {
try {

let thread;
if (!threadId) {
thread = await this.openai.beta.threads.create();
Expand Down Expand Up @@ -63,7 +66,7 @@ class OpenAIService {
}

const latestMessage = assistantMessages[0];

const textContent = latestMessage.content
.filter((content) => content.type === "text")
.map((content) => content.text.value)
Expand Down
28 changes: 26 additions & 2 deletions gurubu-backend/services/pService.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,31 @@ dotenv.config();

class PService {
constructor() {
this.baseUrl = process.env.P_GATEWAY_URL;
// Validate required environment variables
const requiredEnvVars = {
P_GATEWAY_URL: process.env.P_GATEWAY_URL
};

const missingVars = [];
for (const [key, value] of Object.entries(requiredEnvVars)) {
if (!value || value.trim() === '') {
missingVars.push(key);
}
}

if (missingVars.length > 0) {
throw new Error(
`Missing required environment variables for P service: ${missingVars.join(', ')}. ` +
'Please check your .env file and ensure P_GATEWAY_URL is set.'
);
}

// Validate P_GATEWAY_URL format
try {
new URL(this.baseUrl = process.env.P_GATEWAY_URL);
} catch (error) {
throw new Error(`Invalid P_GATEWAY_URL format: ${process.env.P_GATEWAY_URL}. Must be a valid URL.`);
}
}

async getOrganizations() {
Expand Down Expand Up @@ -77,7 +101,7 @@ class PService {
},
}
);

return response.data;
} catch (error) {
console.error("Error searching users:", error);
Expand Down