Stretched Texture on Mesh

Hello there,
I’ve got some questions regarding my code:
How to implement/manipulate texture coordinates / uv mapping here:
Obviously something is wrong with the shader or the mesh class, because the non quadratic texture is always stretched.
How to make it appear in a correct way? (non stretched and repeated texture on my square mesh).
Many thanks in advance.

Full minimal code example, thats shows the problem:

#include <GL/glew.h>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstddef>

class Camera
{
public:
	static const glm::vec3 WorldUp;

	Camera(glm::vec3 position, float pitch = 0.0f, float yaw = -90.0f, float fov = 60.0f);

	void UpdateDirectionVectors();

	glm::mat4 GetProjectionMatrix(float width, float height);
	glm::mat4 GetViewMatrix();

	glm::vec3 position;
	float fov, yaw, pitch;

private:
	glm::vec3 forward, right, up;
};


const glm::vec3 Camera::WorldUp{ 0.0f, 1.0f, 0.0f };

Camera::Camera(glm::vec3 position, float pitch, float yaw, float fov)
	: position(position), pitch(pitch), yaw(yaw), fov(fov), forward(), right(), up()
{

}

glm::mat4 Camera::GetProjectionMatrix(float width, float height)
{
	return glm::perspective(glm::radians(fov), width / height, 0.1f, 100000.0f);           // draw distance 100.0f
}

void Camera::UpdateDirectionVectors()
{
	forward = glm::normalize(glm::vec3(
		glm::cos(glm::radians(yaw)) * glm::cos(glm::radians(pitch)),
		glm::sin(glm::radians(pitch)),
		glm::sin(glm::radians(yaw)) * glm::cos(glm::radians(pitch))
	));

	right = glm::normalize(glm::cross(forward, WorldUp));
	up = glm::normalize(glm::cross(right, forward));
}

glm::mat4 Camera::GetViewMatrix()
{
	return glm::lookAt(position, position + forward, up);
}


class Shader
{
public:
	Shader(const std::string& vertexCode, const std::string& fragmentCode);
	void Use();

	void SetValue(const std::string& name, glm::vec3 value);
	void SetValue(const std::string& name, glm::mat4 value);
private:
	uint32_t programID;
};

Shader::Shader(const std::string& vertexCode, const std::string& fragmentCode)
{
	const char* vertexShaderCode = vertexCode.c_str();
	const char* fragmentShaderCode = fragmentCode.c_str();


	// vertexshader
	size_t vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderCode, nullptr);
	glCompileShader(vertexShader);

	int success{};
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	char infoLog[1024]{};

	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 1024, nullptr, infoLog);
		std::cerr << "Failed to compile shader!\nInfoLog:\n" << infoLog;
	}

	//fragmentshader
	size_t fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderCode, nullptr);
	glCompileShader(fragmentShader);

	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);

	if (!success)
	{
		glGetShaderInfoLog(fragmentShader, 1024, nullptr, infoLog);
		std::cerr << "Failed to compile shader!\nInfoLog:\n" << infoLog;
	}
	//

	programID = glCreateProgram();
	glAttachShader(programID, vertexShader);
	glAttachShader(programID, fragmentShader);
	glLinkProgram(programID);

	glGetProgramiv(programID, GL_LINK_STATUS, &success);

	if (!success)
	{
		glGetProgramInfoLog(programID, 1024, nullptr, infoLog);
		std::cerr << "Failed to link shader!\nInfoLog:\n" << infoLog;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
}

void Shader::Use()
{
	glUseProgram(programID);
}


void Shader::SetValue(const std::string& name, glm::vec3 value)
{
	glUniform3f(glGetUniformLocation(programID, name.c_str()), value.x, value.y, value.z);
}

void Shader::SetValue(const std::string& name, glm::mat4 value)
{
	glUniformMatrix4fv(glGetUniformLocation(programID, name.c_str()), 1, GL_FALSE,
		glm::value_ptr(value));
}


sf::Texture texture0;

class Mesh
{
public:
	Mesh(std::vector<glm::vec3> vertices, std::vector<uint32_t> indices, std::vector<glm::vec2> TexCoords);
	void Draw() const;

	glm::mat4 transformation;

private:
	std::vector<glm::vec3> vertices;
	std::vector<uint32_t> indices;
	std::vector<glm::vec2> TexCoords;

	uint32_t vao, vbo, ebo;
};


Mesh::Mesh(std::vector<glm::vec3> vertices, std::vector<uint32_t> indices, std::vector<glm::vec2> TexCoords)
	: vertices(vertices), indices(indices), TexCoords(TexCoords), vao(), vbo(), ebo()
{
	glGenBuffers(1, &vbo);
	glGenBuffers(1, &ebo);
	glGenVertexArrays(1, &vao);

	glBindVertexArray(vao);

	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(glm::uint32_t), indices.data(), GL_STATIC_DRAW);

	//vertex positions
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);

	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertices.size() * 3, 0);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	glBindVertexArray(0);

	glBindVertexArray(vao);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

	texture0.loadFromFile("coins_seamless.jpg");
	glActiveTexture(GL_TEXTURE0);
	sf::Texture::bind(&texture0);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

}

void Mesh::Draw() const
{
	glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, nullptr);
}


class Object
{
public:
	Object(const Mesh* mesh, glm::vec3 position = {}, glm::vec3 rotation = {}, glm::vec3 scale = glm::vec3(1.0f));
	void Draw(Shader& shader, glm::vec3 color = {});

	glm::mat4 GetTransformationMatrix();

	const Mesh* mesh;
	glm::vec3 position, rotation, scale;
private:

};


Object::Object(const Mesh* mesh, glm::vec3 position, glm::vec3 rotation, glm::vec3 scale)
	: mesh(mesh), position(position), rotation(rotation), scale(scale)
{
}

void Object::Draw(Shader& shader, glm::vec3 color)
{
	shader.SetValue("model", GetTransformationMatrix());
	shader.SetValue("color", color);

	mesh->Draw();
}

glm::mat4 Object::GetTransformationMatrix()
{
	glm::mat4 t = glm::mat4(1.0f);

	t = glm::translate(t, position);
	t = t * glm::mat4_cast(glm::quat(glm::radians(rotation)));
	t = glm::scale(t, scale);

	return t;
}


int main()
{
	const char* vertexShaderCode = "#version 330 core\n"
		"layout (location = 0) in vec3 pos;\n"
		"layout (location = 1) in vec2 uv;\n"
		"uniform mat4 projection;\n"
		"uniform mat4 view;\n"
		"uniform mat4 model;\n"
		"out vec2 TexCoords;\n"

		"void main() { gl_Position = projection * view * model * vec4(pos, 1.0);\n"
		"TexCoords = uv;\n"
		"}\n";

	const char* fragmentShaderCode = "#version 330 core\n"
		"in vec2 TexCoords;\n"
		"out vec4 FragColor;\n"

		"uniform vec3 color;\n"
		"uniform sampler2D sampler;\n"

		//"void main() { FragColor = texture(sampler,TexCoords) * vec4(color, 1.0); }\n";
		"void main() { FragColor = texture(sampler,TexCoords); }\n";


	sf::RenderWindow window(sf::VideoMode(800, 800), "3D OpenGL");

	if (glewInit() != GLEW_OK)
	{
		std::cerr << "Failed to initialize GLEW\n";
		return -1;
	}

	Shader shader(vertexShaderCode, fragmentShaderCode);


	Mesh mesh({
		glm::vec3(0.8f,  0.8f, 0.0f), // top right
		glm::vec3(0.8f, -0.8f, 0.0f), // bottom right
		glm::vec3(-0.8f,-0.8f, 0.0f), // bottom left
		glm::vec3(-0.8f, 0.8f, 0.0f), // top left
		}, { 0,1,3,1,2,3, }, {

		glm::vec2(1.0f,1.0f),		// 1.0f,1.0f
		glm::vec2(1.0f,0.0f),		// 1.0f,0.0f
		glm::vec2(0.0f,0.0f),		// 0.0f,0.0f
		glm::vec2(0.0f,1.0f)		// 0.0f,1.0f
		});



	Camera camera(glm::vec3(0.0f, 0.0f, 3.0f), 0.0f);

	Object object(&mesh, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, -1.0f, 1.0f)); // position, rotation, scale

	bool isFirstMouse = true;
	sf::Vector2i lastMousePos{};

	while (window.isOpen())
	{

		sf::Event event{};
		while (window.pollEvent(event))
		{
			if (event.type == sf::Event::Closed)
				window.close();
			else if (event.type == sf::Event::Resized)
				glViewport(0, 0, window.getSize().x, window.getSize().y);

		}

		camera.UpdateDirectionVectors();




		glClear(GL_COLOR_BUFFER_BIT);

		shader.Use();
		shader.SetValue("view", camera.GetViewMatrix());
		shader.SetValue("projection", camera.GetProjectionMatrix((float)window.getSize().x, (float)window.getSize().y));

		object.Draw(shader, glm::vec3(1.0f, 0.5f, 0.5f));

		window.display();
	}
}