AIcodingmaster

CVpage end

Showing 65 changed files with 1139 additions and 0 deletions

701 KB

2.45 MB

No preview for this file type
1 +from flask import Flask
2 +from flask_migrate import Migrate
3 +from flask_sqlalchemy import SQLAlchemy
4 +
5 +import config
6 +db = SQLAlchemy()
7 +migrate = Migrate()
8 +
9 +def create_app():
10 + app = Flask(__name__)
11 + from .views import workdetail_view,main_view,about_view
12 + #db 설정 등록
13 + app.config.from_object(config)
14 + #ORM(db 코드 추상화) 등록
15 + db.init_app(app)
16 + migrate.init_app(app, db)
17 + from . import models
18 + #블루 프린트 등록
19 + app.register_blueprint(workdetail_view.bp)
20 + app.register_blueprint(main_view.bp)
21 + app.register_blueprint(about_view.bp)
22 + from .filter import format_datetime
23 + app.jinja_env.filters['datetime'] = format_datetime
24 + return app
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
1 +def format_datetime(value, fmt='%Y/%m/%d %H:%M'):
2 + return value.strftime(fmt)
...\ No newline at end of file ...\ No newline at end of file
1 +from flask_wtf import FlaskForm
2 +from wtforms import StringField, TextAreaField
3 +from wtforms.validators import DataRequired
4 +
5 +class ProjectForm(FlaskForm):
6 + projectName = StringField('프로젝트이름', validators=[DataRequired()])
7 + projectType = StringField('타입', validators=[DataRequired()])
8 + pictureName = StringField('video, pic이름', validators=[DataRequired()])
9 + content = TextAreaField('내용', validators=[DataRequired()])
10 + gitAddress = StringField('git주소', validators=[DataRequired()])
1 +from CVpage import db
2 +
3 +
4 +class Project(db.Model):
5 + id = db.Column(db.Integer, primary_key=True)
6 + projectName = db.Column(db.String(200), nullable=False)
7 + projectType = db.Column(db.String(200), nullable=False)
8 + pictureName = db.Column(db.String(200), nullable=False)
9 + content = db.Column(db.Text(), nullable=False)
10 + gitAddress = db.Column(db.String(200), nullable=False)
11 + create_date = db.Column(db.DateTime(), nullable=False)
...\ No newline at end of file ...\ No newline at end of file
1 +.jumbotron {
2 + padding-top: 3rem;
3 + padding-bottom: 3rem;
4 + margin-bottom: 0;
5 + background-color: #fff;
6 +}
7 +@media (min-width: 768px) {
8 + .jumbotron {
9 + padding-top: 6rem;
10 + padding-bottom: 6rem;
11 + }
12 +}
13 +
14 +.nooutline{
15 + border:0;
16 +}
17 +.jumbotron p:last-child {
18 + margin-bottom: 0;
19 +}
20 +
21 +.jumbotron h1 {
22 + font-weight: 300;
23 +}
24 +
25 +.jumbotron .container {
26 + max-width: 40rem;
27 +}
28 +
29 +footer {
30 + padding-top: 3rem;
31 + padding-bottom: 3rem;
32 +}
33 +
34 +footer p {
35 + margin-bottom: .25rem;
36 +}
37 +
38 +header { position: fixed; z-index: 10; top: 0; left: 0; width: 100%; height: 0px; transition: top 0.2s ease-in-out; }
39 +.nav-up { top: -70px;}
40 +
41 +.bg-dark{
42 + background-color: burlywood;
43 +}
44 +.textblack{
45 + color:black;
46 + text-decoration:none;
47 +}
48 +.textblack:hover{
49 + color:#808080;
50 + text-decoration:none;
51 +}
52 +
53 +.sub{
54 + font-size:.5em;
55 + color:#000000;
56 +}
57 +.box{
58 + position: static;
59 + height: 220px;
60 +}
61 +.front{
62 + position: absolute;
63 + top:0;
64 + left:0;
65 + display: none;
66 +}
67 +.back{
68 + position: absolute;
69 + top:0;
70 + left:0;
71 + display: none;
72 +}
73 +.box img:nth-child(2){
74 + opacity: 0;
75 + transition:all 0.3s ease in ease-in-out;
76 +}
77 +.box:hover img:nth-child(2){
78 + opacity: 1;
79 + transition:all 0.3s ease in ease-in-out;
80 +}
81 +.form{
82 +}
This diff could not be displayed because it is too large.
1 +.bgImage{
2 + -webkit-filter: brightness(70%);filter: brightness(70%);
3 + position: absolute;
4 + top:0;
5 + left:0;
6 + z-index: -1;
7 + height: 100%;
8 + width:100%;
9 + animation: fadeIn 0.5s linear;
10 +}
11 +.bgImg{
12 + -webkit-filter: brightness(70%);filter: brightness(70%);
13 + position: absolute;
14 + top:0;
15 + left:0;
16 + z-index: -1;
17 + height: 100%;
18 + width:100%;
19 +}
20 +@keyframes fadeIn{
21 + from{
22 + opacity:0;
23 + }
24 + to{
25 +
26 + opacity:1;
27 + }
28 +}
29 +html, body {
30 +
31 + margin: 0;
32 +
33 + height: 100%;
34 +
35 + overflow: hidden;
36 +
37 +}
38 +.detail-container{
39 + display:grid;
40 + grid-template-columns:10% 1fr;
41 + grid-template-rows:20% 60% 1fr;
42 + height:100%;
43 + grid-gap:10px;
44 + grid-template-areas:
45 + "header header"
46 + "side main"
47 + "side footer"
48 +}
49 +header{
50 + grid-area:header;
51 +}
52 +.main{
53 + grid-area:main;
54 + padding-left:3rem;
55 +}
56 +.side{
57 + grid-area: side;
58 + display: flex;
59 + justify-content: center;
60 + padding-top:100%;
61 +}
62 +.footer{
63 + grid-area:footer;
64 +}
65 +.textwhite{
66 + color:rgb(255, 255, 255);
67 + text-decoration:none;
68 + border:2px solid white;
69 + padding:1px 5px 3px 5px;
70 + transition:all 0.2s;
71 + margin-right:0.5rem;
72 + }
73 +.textwhite:hover{
74 + color:#cecece;
75 + text-decoration:none;
76 + border:4px solid #cecece;
77 + padding:1px 5px 3px 5px;
78 + margin-right:0.5rem;
79 + }
80 +
81 +.textwhitebx{
82 + color:rgb(255, 255, 255);
83 + text-decoration:none;
84 + transition:all 0.2s;
85 + }
86 +.textwhitebx:hover{
87 + color:#cecece;
88 + text-decoration:none;
89 + padding:1px 5px 3px 5px;
90 + margin-right:0.5rem;
91 +}
92 +.left-footer{
93 + width:35%;
94 + float:left;
95 + box-sizing:border-box;
96 + margin-right:15%;
97 + text-align: right;
98 +}
99 +
100 +.right-footer{
101 + width:35%;
102 + float:right;
103 + position: static;
104 + box-sizing:border-box;
105 + text-align: left;
106 + margin-right:15%;
107 +}
108 +.bottomBorderL a,.bottomBorderR a{
109 + -webkit-transition: all 0.3s ease;
110 + transition: all 0.3s ease;
111 +}
112 +.bottomBorderL a:hover{
113 + border-bottom: solid 2px white;
114 + border-left:solid 2px white;
115 + width: 100%;
116 +}
117 +.bottomBorderR a:hover{
118 + border-bottom: solid 2px white;
119 + border-right:solid 2px white;
120 + width: 100%;
121 +}
122 +
1 +//nav바 추적
2 +var lastScrollTop = 0;
3 +var delta = 5; // 동작의 구현이 시작되는 위치
4 +var navbarHeight = 70; // 영향을 받을 요소를 선택
5 +var didScroll; // 스크롤시에 사용자가 스크롤했다는 것을 알림
6 +$(window).scroll(function(event){ didScroll = true; }); // hasScrolled()를 실행하고 didScroll 상태를 재설정
7 +setInterval(function() { if (didScroll) { hasScrolled(); didScroll = false; } }, 250);
8 +function hasScrolled() {
9 + var st = $(this).scrollTop();
10 + if (Math.abs(lastScrollTop-st) <= delta) return;
11 + // If current position > last position AND scrolled past navbar...
12 + if (st > lastScrollTop && st > navbarHeight){
13 + // Scroll Down
14 + if($(`#navbarHeader`).hasClass(`show`))
15 + {
16 + n=$(`#navbarHeader`);
17 + n.removeClass(`show`);
18 +
19 + }
20 + $(`header`).removeClass(`nav-down`).addClass(`nav-up`);
21 + }
22 + else { // Scroll Up
23 + // If did not scroll past the document (possible on mac)...
24 + if($(`#navbarHeader`).hasClass(`show`))
25 + {
26 + n=$(`#navbarHeader`)
27 + n.removeClass(`show`)
28 + return
29 + }
30 + if(st + $(window).height() < $(document).height())
31 + {
32 + $(`header`).removeClass(`nav-up`).addClass(`nav-down`);
33 + }
34 + }
35 + lastScrollTop = st;
36 +
37 +}
38 +const navbutton=document.querySelector('.navButton')
39 +const maindiv=document.querySelector('.belowHeader')
40 +navbutton.addEventListener('onclick',pushMain)
41 +function pushMain(){
42 + maindiv.style.transform="translate3d(0px, px, 0px)";
43 +}
44 +function zoomIn(event) {
45 + event.target.style.transform = "scale(1.1)";
46 + event.target.style.zIndex = 1;
47 + event.target.style.transition = "all 0.5s";
48 + div=event.target.parentNode.parentNode;
49 + content=div.querySelector(`.card-body`);
50 + content.style.transform = "translate3d(0px, -150px, 0px)";
51 + content.style.transition = "all 0.5s";
52 +}
53 +
54 +function zoomOut(event) {
55 + event.target.style.transform = "scale(1)";
56 + event.target.style.zIndex = 1;
57 + event.target.style.transition = "all 0.5s";
58 + div=event.target.parentNode.parentNode;
59 + content=div.querySelector(`.card-body`);
60 + content.style.transform = "translate3d(0px, 0px, 0px)";
61 + content.style.transition = "all 0.5s";
62 +}
This diff is collapsed. Click to expand it.
1 +$(".box").each(function(){
2 + var box=$(this)
3 + var boxImgs=$(this).children('img')
4 + var myAnimation = new hoverEffect({
5 + parent: box[0],
6 + intensity: 1.0,
7 + speedIn:1.3,
8 + speedOut:1.3,
9 + angle:Math.PI/2,
10 + image1: boxImgs[0].getAttribute('src'),
11 + image2: boxImgs[1].getAttribute('src'),
12 + displacementImage: box[0].getAttribute('displacementImage')
13 + });
14 +})
...\ No newline at end of file ...\ No newline at end of file
1 +const strong=document.querySelector('strong.textblack')
2 +const card=document.querySelector('svg.bi-card-list')
3 +const playBtn=document.querySelector('svg.bi-file-play')
4 +
5 +strong.classList.remove('textblack')
6 +strong.classList.add('text-white')
7 +card.setAttribute('fill','white')
8 +function playBtnOverHandler(){
9 + playBtn.setAttribute('fill','black');
10 + playBtn.style.transform= "scale(1.3)";
11 + playBtn.style.transition= 'all 0.3s';
12 +}
13 +function playBtnOutHandler(){
14 + playBtn.setAttribute('fill','white');
15 + playBtn.style.transform= "scale(1.0)";
16 + playBtn.style.transition= 'all 0.3s';
17 +}
18 +playBtn.addEventListener("mouseover",playBtnOverHandler)
19 +playBtn.addEventListener("mouseout",playBtnOutHandler)
20 +//playBtn.addEventListener("onclick",playBtnHandler)어디서 컨트롤할지 안정함
...\ No newline at end of file ...\ No newline at end of file
1 +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("three"),require("gsap/TweenMax")):"function"==typeof define&&define.amd?define(["three","gsap/TweenMax"],t):e.hoverEffect=t(e.THREE,e.TweenMax)}(this,function(e,t){return t=t&&t.hasOwnProperty("default")?t.default:t,function(n){function i(){for(var e=arguments,t=0;t<arguments.length;t++)if(void 0!==e[t])return e[t]}console.log("%c Hover effect by Robin Delaporte: https://github.com/robin-dela/hover-effect ","color: #bada55; font-size: 0.8rem");var r=n.parent,o=n.displacementImage,a=n.image1,s=n.image2,f=i(n.imagesRatio,1),d=i(n.intensity1,n.intensity,1),l=i(n.intensity2,n.intensity,1),u=i(n.angle,Math.PI/4),v=i(n.angle1,u),m=i(n.angle2,3*-u),c=i(n.speedIn,n.speed,1.6),p=i(n.speedOut,n.speed,1.2),g=i(n.hover,!0),h=i(n.easing,Expo.easeOut),y=i(n.video,!1);if(r)if(a&&s&&o){var x=new e.Scene,F=new e.OrthographicCamera(r.offsetWidth/-2,r.offsetWidth/2,r.offsetHeight/2,r.offsetHeight/-2,1,1e3);F.position.z=1;var w=new e.WebGLRenderer({antialias:!1,alpha:!0});w.setPixelRatio(2),w.setClearColor(16777215,0),w.setSize(r.offsetWidth,r.offsetHeight),r.appendChild(w.domElement);var L=function(){w.render(x,F)},H=new e.TextureLoader;H.crossOrigin="";var E,W,V=H.load(o,L);if(V.magFilter=V.minFilter=e.LinearFilter,y){var M=function(){requestAnimationFrame(M),w.render(x,F)};M(),(y=document.createElement("video")).autoplay=!0,y.loop=!0,y.src=a,y.load();var P=document.createElement("video");P.autoplay=!0,P.loop=!0,P.src=s,P.load();var R=new e.VideoTexture(y),T=new e.VideoTexture(P);R.magFilter=T.magFilter=e.LinearFilter,R.minFilter=T.minFilter=e.LinearFilter,P.addEventListener("loadeddata",function(){P.play(),(T=new e.VideoTexture(P)).magFilter=e.LinearFilter,T.minFilter=e.LinearFilter,C.uniforms.texture2.value=T},!1),y.addEventListener("loadeddata",function(){y.play(),(R=new e.VideoTexture(y)).magFilter=e.LinearFilter,R.minFilter=e.LinearFilter,C.uniforms.texture1.value=R},!1)}else R=H.load(a,L),T=H.load(s,L),R.magFilter=T.magFilter=e.LinearFilter,R.minFilter=T.minFilter=e.LinearFilter;var U=f;r.offsetHeight/r.offsetWidth<U?(E=1,W=r.offsetHeight/r.offsetWidth/U):(E=r.offsetWidth/r.offsetHeight*U,W=1);var C=new e.ShaderMaterial({uniforms:{intensity1:{type:"f",value:d},intensity2:{type:"f",value:l},dispFactor:{type:"f",value:0},angle1:{type:"f",value:v},angle2:{type:"f",value:m},texture1:{type:"t",value:R},texture2:{type:"t",value:T},disp:{type:"t",value:V},res:{type:"vec4",value:new e.Vector4(r.offsetWidth,r.offsetHeight,E,W)},dpr:{type:"f",value:window.devicePixelRatio}},vertexShader:"\nvarying vec2 vUv;\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}\n",fragmentShader:"\nvarying vec2 vUv;\n\nuniform float dispFactor;\nuniform float dpr;\nuniform sampler2D disp;\n\nuniform sampler2D texture1;\nuniform sampler2D texture2;\nuniform float angle1;\nuniform float angle2;\nuniform float intensity1;\nuniform float intensity2;\nuniform vec4 res;\nuniform vec2 parent;\n\nmat2 getRotM(float angle) {\n float s = sin(angle);\n float c = cos(angle);\n return mat2(c, -s, s, c);\n}\n\nvoid main() {\n vec4 disp = texture2D(disp, vUv);\n vec2 dispVec = vec2(disp.r, disp.g);\n\n vec2 uv = 0.5 * gl_FragCoord.xy / (res.xy) ;\n vec2 myUV = (uv - vec2(0.5))*res.zw + vec2(0.5);\n\n\n vec2 distortedPosition1 = myUV + getRotM(angle1) * dispVec * intensity1 * dispFactor;\n vec2 distortedPosition2 = myUV + getRotM(angle2) * dispVec * intensity2 * (1.0 - dispFactor);\n vec4 _texture1 = texture2D(texture1, distortedPosition1);\n vec4 _texture2 = texture2D(texture2, distortedPosition2);\n gl_FragColor = mix(_texture1, _texture2, dispFactor);\n}\n",transparent:!0,opacity:1}),b=new e.PlaneBufferGeometry(r.offsetWidth,r.offsetHeight,1),D=new e.Mesh(b,C);x.add(D),g&&(r.addEventListener("mouseenter",_),r.addEventListener("touchstart",_),r.addEventListener("mouseleave",z),r.addEventListener("touchend",z)),window.addEventListener("resize",function(t){r.offsetHeight/r.offsetWidth<U?(E=1,W=r.offsetHeight/r.offsetWidth/U):(E=r.offsetWidth/r.offsetHeight*U,W=1),D.material.uniforms.res.value=new e.Vector4(r.offsetWidth,r.offsetHeight,E,W),w.setSize(r.offsetWidth,r.offsetHeight),L()}),this.next=_,this.previous=z}else console.warn("One or more images are missing");else console.warn("Parent missing");function _(){t.to(C.uniforms.dispFactor,c,{value:1,ease:h,onUpdate:L,onComplete:L})}function z(){t.to(C.uniforms.dispFactor,p,{value:0,ease:h,onUpdate:L,onComplete:L})}}});
2 +//# sourceMappingURL=hover-effect.umd.js.map
This diff is collapsed. Click to expand it.
1 +<!doctype html>
2 +<html lang="en">
3 + <head>
4 + <meta charset="utf-8">
5 + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6 + <meta name="description" content="">
7 + <title>CVpage</title>
8 +
9 +
10 + <!-- Bootstrap core CSS -->
11 +<link href="{{url_for('static',filename='css/bootstrap.min.css')}}" rel="stylesheet">
12 +<link href="{{url_for('static',filename='css/about.css')}}" rel="stylesheet">
13 + <style>
14 + .bd-placeholder-img {
15 + font-size: 1.125rem;
16 + text-anchor: middle;
17 + -webkit-user-select: none;
18 + -moz-user-select: none;
19 + -ms-user-select: none;
20 + user-select: none;
21 + }
22 +
23 + @media (min-width: 768px) {
24 + .bd-placeholder-img-lg {
25 + font-size: 3.5rem;
26 + }
27 + }
28 + </style>
29 + <!-- Custom styles for this template -->
30 + </head>
31 + <body>
32 + {%include 'navbar.html'%}
33 +<div class="sub" style="z-index: 9999999;">
34 + CopyWrite KHJ<br>
35 + <br>
36 + <br>
37 + <br>
38 + <br>
39 + <br>
40 + <br>
41 +</div>
42 +<div class=belowHeader>
43 +<main role="main">
44 + <div class="album py-5">
45 + <div class="container">
46 + <div class="row">
47 +<!-- project card start-->
48 +{%if g.user%}
49 +<div class="col-md-4">
50 + <a class="card mb-4 nooutline" href="{{url_for('about.add')}}">
51 + <img src="{{url_for('static',filename='img/plus.png')}}" onmouseenter=zoomIn(event) onmouseleave=zoomOut(event)>
52 + </img>
53 + </a>
54 + <div class="card-body">
55 + <p class="card-text">Project Name</p>
56 + <div class="d-flex justify-content-between align-items-center">
57 + <div class="btn-group">
58 + <button type="button" class="btn btn-sm btn-outline-secondary">btn</button>
59 + </div>
60 + <small class="text-muted">date</small>
61 + </div>
62 + </div>
63 +</div>
64 +{%endif%}
65 +{%if w_list%}
66 +{%for work in w_list%}
67 + <div class="col-md-4">
68 + <a class="card mb-4 nooutline" href="{{url_for('detail.detail',project_id=work.id)}}">
69 + <div class='box' onmouseenter=zoomIn(event) onmouseleave=zoomOut(event) displacementImage="{{url_for('static',filename='img/distortion.jpg')}}">
70 + <img class=front src="{{url_for('static',filename='img/'+work.pictureName+'1.jpg')}}" width=100% height=225 alt="" onmouseenter=zoomIn(event) onmouseleave=zoomOut(event)>
71 + <img class=back src="{{url_for('static',filename='img/'+work.pictureName+'2.jpg')}}" width=100% height=225 alt="" onmouseenter=zoomIn(event) onmouseleave=zoomOut(event)>
72 + </div>
73 + </a>
74 + <div class="card-body">
75 + <p class="card-text">{{work.projectName}}</p>
76 + <div class="d-flex justify-content-between align-items-center">
77 + <div class="btn-group">
78 + <button type="button" onclick="location.href='{{work.gitAddress}}'" class="btn btn-sm btn-outline-secondary">git</button>
79 + <a href="{{url_for('detail.video',project_id=work.id)}}">
80 + <button type="button" class="btn btn-sm btn-outline-secondary btnvideo">video</button>
81 + </a>
82 + {%if g.user%}
83 + <a href="{{url_for('about.delete',project_id=work.id)}}">
84 + <button type="button" class="btn btn-sm btn-outline-secondary btnvideo">delete</button>
85 + </a>
86 + <a href="{{url_for('about.modify',project_id=work.id)}}">
87 + <button type="button" class="btn btn-sm btn-outline-secondary btnvideo">modify</button>
88 + </a>
89 + {%endif%}
90 + </div>
91 + <small class="text-muted">{{work.create_date|datetime}}</small>
92 + </div>
93 + </div>
94 + </div>
95 +{%endfor%}
96 +{%endif%}
97 +<!-- project card end-->
98 +
99 +
100 + </div>
101 + </div>
102 + </div>
103 +
104 +</main>
105 +<br><br><br><br><br><br><br>
106 +<footer class="text-muted" style="margin-bottom:30rem">
107 + <div class="container">
108 + <p class="float-right">
109 + <a href="#" class="textblack">Back to top</a>
110 + </p>
111 + <p>
112 + <ul>
113 + <h2 id=aboutme>
114 + About Me
115 + </h2>
116 + <br>
117 + <li>
118 + HyungJin Kweon
119 + </li>
120 + <li>
121 + KyungHee Univ.
122 + </li>
123 + <li>
124 + email : intimate0305@khu.ac.kr
125 + </li>
126 + <li>
127 + I'm junior programmer interested in Computer Vision.
128 + </li>
129 + </ul>
130 + </p>
131 +</footer>
132 +
133 +</div>
134 +<script src="{{url_for('static',filename='js/jquery-3.5.1.min.js')}}"></script>
135 +<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r120/three.min.js"></script>
136 +<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
137 +<script src="{{url_for('static',filename='js/hover-effect.umd.js')}}"></script>
138 +<script src="{{url_for('static',filename='js/about.js')}}"></script>
139 +<script src="{{url_for('static',filename='js/custom.js')}}"></script>
140 +<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
141 +<script src="{{url_for('static',filename='js/bootstrap.bundle.min.js')}}"></script>
142 +</body>
143 +</html>
1 +<!doctype html>
2 +<html lang="ko">
3 +<head>
4 + <meta charset="utf-8">
5 + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
6 + <title>CVpage</title>
7 + <link href="{{url_for('static',filename='css/bootstrap.min.css')}}" rel="stylesheet">
8 + <link href="{{url_for('static',filename='css/about.css')}}" rel="stylesheet">
9 + <link href="{{url_for('static',filename='css/detail.css')}}" rel="stylesheet">
10 +</head>
11 +<body>
12 +{% block content %}
13 +{% endblock %}
14 +<script src="{{url_for('static',filename='js/jquery-3.5.1.min.js')}}"></script>
15 +<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r120/three.min.js"></script>
16 +<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
17 +<script src="{{url_for('static',filename='js/hover-effect.umd.js')}}"></script>
18 +<script src="{{url_for('static',filename='js/about.js')}}"></script>
19 +<script src="{{url_for('static',filename='js/custom.js')}}"></script>
20 +<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
21 +<script src="{{url_for('static',filename='js/bootstrap.bundle.min.js')}}"></script>
22 +<script src="{{url_for('static',filename='js/detail.js')}}"></script>
23 +</body>
24 +</html>
...\ No newline at end of file ...\ No newline at end of file
1 +<header class="nav-container">
2 + <div class="collapse bg-white" id="navbarHeader" >
3 + <div class="container">
4 + <div class="row">
5 + <div class="col-sm-8 col-md-7 py-4"><p>
6 + <h4 class="text-black">CVpage</p>
7 + <p class="text-muted">
8 + This site is designed for personally read papers and project management.</p></h4>
9 + </div>
10 + <div class="col-sm-4 offset-md-1 py-4">
11 + <h4 class="text-black">Menu</h4>
12 + <ul class="list-unstyled">
13 + <li><a href="{{url_for('about.about')}}#aboutme" class="textblack">About me</a></li>
14 + <li><a href="https://wikidocs.net/book/5049" class="textblack">Paper Read</a></li>
15 + <li><a href="https://github.com/AIcodingmaster" class="textblack">Github</a></li>
16 + </ul>
17 + </div>
18 + </div>
19 + </div>
20 + </div>
21 + <div class="wrap_gnb navbar navbar-black bg-black shadow-sm">
22 + <div class="container d-flex justify-content-between">
23 + <a href="{{url_for('about.about')}}" class="navbar-brand d-flex align-items-center">
24 + <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-card-list" fill="black" xmlns="http://www.w3.org/2000/svg" style="margin:10px;">
25 + <path fill-rule="evenodd" d="M14.5 3h-13a.5.5 0 0 0-.5.5v9a.5.5 0 0 0 .5.5h13a.5.5 0 0 0 .5-.5v-9a.5.5 0 0 0-.5-.5zm-13-1A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13z"/>
26 + <path fill-rule="evenodd" d="M5 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 5 8zm0-2.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0 5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5z"/>
27 + <circle cx="3.5" cy="5.5" r=".5"/>
28 + <circle cx="3.5" cy="8" r=".5"/>
29 + <circle cx="3.5" cy="10.5" r=".5"/>
30 + </svg>
31 + <strong class=textblack>Project</strong>
32 + </a>
33 + {%if g.user%}
34 + <a href="{{url_for('main.logout')}}">
35 + <strong class="textblack" style="opacity: 0.5;margin-left:-30rem">({{g.user}})</strong>
36 + </a>
37 + {%endif%}
38 + <button class=navButton style="background-color:white;border:0;outline:0" type="button" data-toggle="collapse" data-target="#navbarHeader" aria-controls="navbarHeader" aria-expanded="false" aria-label="Toggle navigation">
39 + <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-caret-down-fill" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
40 + <path d="M7.247 11.14L2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/>
41 + </svg>
42 + </button>
43 + </div>
44 + </div>
45 + </header>
...\ No newline at end of file ...\ No newline at end of file
1 +{%extends 'base.html'%}
2 +{%block content%}
3 +<form class="form" method="POST" enctype="multipart/form-data">
4 + <div>
5 + {{ form.csrf_token }}
6 + {{form.projectName.label}}
7 + {{form.projectName(class="form-control")}}
8 + {{form.projectType.label}}
9 + {{form.projectType(class="form-control")}}
10 + {{form.pictureName.label}}
11 + {{form.pictureName(class="form-control")}}
12 + {{form.content.label}}
13 + {{form.content(class="form-control")}}
14 + {{form.gitAddress.label}}
15 + {{form.gitAddress(class="form-control")}}
16 + 비디오: <input type="file" name="video" id="">
17 + 이미지1:<input type="file" name="pic1" id="">
18 + 이미지2:<input type="file" name="pic2" id="">
19 + <br>
20 + <button type="submit" class="btn btn-primary">submit</button>
21 + </div>
22 +
23 +</form>
24 +{%endblock%}
...\ No newline at end of file ...\ No newline at end of file
1 +{%extends 'base.html'%}
2 +{%block content%}
3 +<video src="{{url_for('static',filename='video/{}.mp4'.format(p.pictureName))}}" width="100%" height="100%" controls></video>
4 +{%endblock%}
...\ No newline at end of file ...\ No newline at end of file
1 +<!DOCTYPE html>
2 +<html>
3 + <head>
4 + <meta charset="utf-8">
5 + <meta name="viewport" content="width=device-width">
6 + <title>CVpage</title>
7 + <link href="{{url_for('static',filename='css/detail.css')}}" rel="stylesheet" type="text/css" />
8 + <link href="{{url_for('static',filename='css/bootstrap.min.css')}}" rel="stylesheet">
9 + <link href="{{url_for('static',filename='css/about.css')}}" rel="stylesheet">
10 + </head>
11 + <body>
12 + {%include 'navbar.html'%}
13 + <div class="detail-container">
14 + <a class="side" href="{{url_for('detail.video',project_id=p.id)}}">
15 + <svg width="5em" height="5em" viewBox="0 0 16 16" class="bi bi-file-play" fill="white" xmlns="http://www.w3.org/2000/svg">
16 + <path fill-rule="evenodd" d="M4 0h8a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm0 1a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H4z"/>
17 + <path d="M6 10.117V5.883a.5.5 0 0 1 .757-.429l3.528 2.117a.5.5 0 0 1 0 .858l-3.528 2.117a.5.5 0 0 1-.757-.43z"/>
18 + </svg>
19 + </a>
20 + <div class="main">
21 + <div class="id_workType">
22 + <h5 class="text-white">
23 + # {{p.id}} / {{p.projectType}}
24 + </h5>
25 + </div>
26 + <br>
27 + <h1 class="text-white">
28 + <div class="projectName">
29 + <strong>
30 + {{p.projectName}}
31 + </strong>
32 + </div>
33 + </h1>
34 + <br>
35 + <h6 class="text-white">
36 + <div class="projectContent">
37 + {{p.content}}
38 + </div>
39 + </h6>
40 + <br>
41 + <span>
42 + <strong class="text-white" style="margin-right: 0.5em">
43 + More :
44 + </strong>
45 + </span>
46 + <span class="gitAddress">
47 + <strong>
48 + <a class="textwhite" href="{{p.gitAddress}}">git</a>
49 + </strong>
50 + </span>
51 + <span class="video">
52 + <strong>
53 + <a class="textwhite" href="{{url_for('detail.video',project_id=p.id)}}">video</a>
54 + </strong>
55 + </span>
56 + </div>
57 + <div class="footer" >
58 + <h5>
59 + <span class="left-footer">
60 + {%if bp%}
61 + <div class="text-white">
62 + <strong>
63 + #{{bp.id}}
64 + </strong>
65 + </div>
66 + <div class=bottomBorderL>
67 + <a class="textwhitebx" href="{{url_for('detail.detail',project_id=bp.id,last_picture=p.pictureName)}}">
68 + <strong>
69 + {{bp.projectName}}
70 + </strong>
71 + </a>
72 + </div>
73 + {%endif%}
74 + </span>
75 + <span class="right-footer">
76 + {%if np%}
77 + <div class="text-white">
78 + <strong>
79 + #{{np.id}}
80 + </strong>
81 + </div>
82 + <div>
83 + <strong class=bottomBorderR>
84 + <a class="textwhitebx" href="{{url_for('detail.detail',project_id=np.id,last_picture=p.pictureName)}}">
85 + {{np.projectName}}
86 + </a>
87 + </strong>
88 + </div>
89 + {%endif%}
90 + </span>
91 + </h5>
92 + </div>
93 + </div>
94 + <!--
95 + {%if last_picture%}
96 +
97 + <div class='box' displacementImage="{{url_for('static',filename='img/distortion.jpg')}}">
98 + <img class="front bgImg" src="{{url_for('static',filename='img/'+last_picture+'2.jpg')}}" alt="" >
99 + <img class="back bgImg" src="{{url_for('static',filename='img/'+p.pictureName+'2.jpg')}}" alt="">
100 + </div>
101 +
102 + {%else%}
103 + {%endif%}
104 +-->
105 + <img class="bgImage" src="{{url_for('static',filename='img/{}1.jpg'.format(p.pictureName))}}" alt="">
106 + <script src="{{url_for('static',filename='js/detail.js')}}"></script>
107 + <script src="{{url_for('static',filename='js/jquery-3.5.1.min.js')}}"></script>
108 + <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r120/three.min.js"></script>
109 + <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>
110 + <script src="{{url_for('static',filename='js/hover-effect.umd.js')}}"></script>
111 + <script src="{{url_for('static',filename='js/about.js')}}"></script>
112 + <script src="{{url_for('static',filename='js/custom.js')}}"></script>
113 + <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
114 + <script src="{{url_for('static',filename='js/bootstrap.bundle.min.js')}}"></script>
115 + </body>
116 +</html>
...\ No newline at end of file ...\ No newline at end of file
1 +{%extends 'base.html'%}
2 +{%block content%}
3 +{% include "form_errors.html" %}
4 +{%endblock%}
...\ No newline at end of file ...\ No newline at end of file
1 +from flask import Blueprint,render_template,url_for,session,g,redirect,request
2 +from werkzeug.utils import secure_filename
3 +from CVpage.models import Project,db
4 +from CVpage.form import ProjectForm
5 +from datetime import datetime
6 +import os
7 +bp = Blueprint('about', __name__, url_prefix='/about/')
8 +
9 +@bp.route('/')
10 +def about():
11 + work_list=Project.query.order_by(Project.create_date.desc())
12 + return render_template('about/about.html',w_list=work_list)
13 +@bp.route('/add/',methods=('GET','POST'))
14 +def add():
15 + form=ProjectForm()
16 + if request.method =="POST" and form.validate_on_submit():
17 + p=Project(projectName=form.projectName.data,
18 + projectType=form.projectType.data,
19 + pictureName=form.pictureName.data,
20 + content=form.content.data,
21 + gitAddress=form.content.data,
22 + create_date=datetime.now())
23 + pic1=request.files['pic1']
24 + pic2=request.files['pic2']
25 + video=request.files['video']
26 + pictureName=form.pictureName.data
27 + pic1.save('/home/ubuntu/projects/CVpage/CVpage/static/img/'+secure_filename(pictureName+'1.jpg'))
28 + pic2.save('/home/ubuntu/projects/CVpage/CVpage/static/img/'+secure_filename(pictureName+'2.jpg'))
29 + video.save('/home/ubuntu/projects/CVpage/CVpage/static/video/'+secure_filename(pictureName+'.mp4'))
30 + db.session.add(p)
31 + db.session.commit()
32 + return redirect(url_for('about.about'))
33 + else:
34 + return render_template('project_form.html', form=form)
35 +
36 +@bp.route('/delete/<int:project_id>')
37 +def delete(project_id):
38 + p=Project.query.get(project_id)
39 + if g.user is "admin":
40 + import os
41 + os.remove(f'./CVpage/static/img/{p.pictureName}1.jpg')
42 + os.remove(f'./CVpage/static/img/{p.pictureName}2.jpg')
43 + os.remove(f'./CVpage/static/video/{p.pictureName}.mp4')
44 + db.session.delete(p)
45 + db.session.commit()
46 + return redirect(url_for('about.about'))
47 +
48 +@bp.route('/modify/<int:project_id>', methods=('GET','POST'))
49 +def modify(project_id):
50 + p=Project.query.get(project_id)
51 + if request.method =="POST":#작성을 하고 form태그의 post요청으로 들어간 것
52 + form = ProjectForm()
53 + bpicN=p.pictureName
54 + if g.user is "admin" and form.validate_on_submit():
55 + pic1=request.files['pic1']
56 + pic2=request.files['pic2']
57 + video=request.files['video']
58 + form.populate_obj(p)
59 + if pic1 is None or pic2 is None or video is None:
60 + return render_template('project_form.html', form=form)
61 + os.remove('/home/ubuntu/projects/CVpage/CVpage/static/img/'+secure_filename(bpicN+'1.jpg'))
62 + os.remove('/home/ubuntu/projects/CVpage/CVpage/static/img/'+secure_filename(bpicN+'2.jpg'))
63 + os.remove('/home/ubuntu/projects/CVpage/CVpage/static/video/'+secure_filename(bpicN+'.mp4'))
64 + pic1.save('/home/ubuntu/projects/CVpage/CVpage/static/img/'+secure_filename(form.pictureName.data+'1.jpg'))
65 + pic2.save('/home/ubuntu/projects/CVpage/CVpage/static/img/'+secure_filename(form.pictureName.data+'2.jpg'))
66 + video.save('/home/ubuntu/projects/CVpage/CVpage/static/video/'+secure_filename(form.pictureName.data+'.mp4'))
67 + db.session.commit()
68 + return redirect(url_for('about.about'))
69 + else:#다른 html에서 접근한 것(GET요청일 경우)
70 + form = ProjectForm(obj=p)#기존 데이터를 대입시켜서 리턴
71 + return render_template('project_form.html', form=form)
72 +
73 +@bp.route('/admin/<int:pw>')
74 +def admin(pw):
75 + if pw==123:
76 + session.clear()
77 + session['pw']=123
78 + return redirect(url_for('about.about'))
79 + else:
80 + return redirect(url_for('about.about'))
1 +from flask import Blueprint,redirect,url_for,session,g
2 +bp = Blueprint('main', __name__, url_prefix='/')
3 +
4 +@bp.before_app_request
5 +def load_logged_in_user():
6 + pw= session.get('pw')
7 + if pw is 123:
8 + g.user = "admin"
9 +
10 +@bp.route('/logout/')
11 +def logout():
12 + session.clear()
13 + return redirect(url_for('about.about'))
14 +
15 +@bp.route('/admin/<int:pw>')
16 +def admin(pw):
17 + if pw==123:
18 + session.clear()
19 + session['pw']=123
20 + return redirect(url_for('about.about'))
21 + else:
22 + return redirect(url_for('about.about'))
23 +
24 +@bp.route('/')
25 +def index():
26 + return redirect(url_for('about.about'))
...\ No newline at end of file ...\ No newline at end of file
1 +from flask import Blueprint,render_template,request
2 +from CVpage.models import Project
3 +bp = Blueprint('detail', __name__, url_prefix='/detail/')
4 +
5 +@bp.route('/<int:project_id>')
6 +def detail(project_id):
7 + p=Project.query.get(project_id)
8 + bp=Project.query.get(project_id+1)
9 + np=Project.query.get(project_id-1)
10 + last_picture=request.args.get('last_picture',None)#key값 p를 찾아보고 없으면 None반환
11 + if last_picture==None:
12 + return render_template('work/work_detail.html',p=p,bp=bp,np=np)
13 + else:
14 + return render_template('work/work_detail.html',p=p,bp=bp,np=np,last_picture=last_picture)
15 +
16 +@bp.route('/video/<int:project_id>')
17 +def video(project_id):
18 + p=Project.query.get(project_id)
19 + return render_template('/video.html',p=p)
...\ No newline at end of file ...\ No newline at end of file
1 +# CVpage with Flask, Vanilla JS, JQuery
2 +![화면1](1.png)
3 +![화면2](2.png)
4 +requirements : Flask, Flask-Migrate
5 +
6 +CVpage에서 flask run 실행
7 +http://localhost:5000/에서 확인 가능
8 +url : http://15.165.162.81:5000 or http://khj.kr
No preview for this file type
No preview for this file type
1 +import os
2 +
3 +BASE_DIR = os.path.dirname(__file__)
4 +SQLALCHEMY_DATABASE_URI = 'sqlite:///{}'.format(os.path.join(BASE_DIR, 'CVpage.db'))
5 +SQLALCHEMY_TRACK_MODIFICATIONS = False
6 +SECRET_KEY = "dev"
...\ No newline at end of file ...\ No newline at end of file
1 +Generic single-database configuration.
...\ No newline at end of file ...\ No newline at end of file
No preview for this file type
No preview for this file type
1 +# A generic, single database configuration.
2 +
3 +[alembic]
4 +# template used to generate migration files
5 +# file_template = %%(rev)s_%%(slug)s
6 +
7 +# set to 'true' to run the environment during
8 +# the 'revision' command, regardless of autogenerate
9 +# revision_environment = false
10 +
11 +
12 +# Logging configuration
13 +[loggers]
14 +keys = root,sqlalchemy,alembic
15 +
16 +[handlers]
17 +keys = console
18 +
19 +[formatters]
20 +keys = generic
21 +
22 +[logger_root]
23 +level = WARN
24 +handlers = console
25 +qualname =
26 +
27 +[logger_sqlalchemy]
28 +level = WARN
29 +handlers =
30 +qualname = sqlalchemy.engine
31 +
32 +[logger_alembic]
33 +level = INFO
34 +handlers =
35 +qualname = alembic
36 +
37 +[handler_console]
38 +class = StreamHandler
39 +args = (sys.stderr,)
40 +level = NOTSET
41 +formatter = generic
42 +
43 +[formatter_generic]
44 +format = %(levelname)-5.5s [%(name)s] %(message)s
45 +datefmt = %H:%M:%S
1 +from __future__ import with_statement
2 +
3 +import logging
4 +from logging.config import fileConfig
5 +
6 +from sqlalchemy import engine_from_config
7 +from sqlalchemy import pool
8 +
9 +from alembic import context
10 +
11 +# this is the Alembic Config object, which provides
12 +# access to the values within the .ini file in use.
13 +config = context.config
14 +
15 +# Interpret the config file for Python logging.
16 +# This line sets up loggers basically.
17 +fileConfig(config.config_file_name)
18 +logger = logging.getLogger('alembic.env')
19 +
20 +# add your model's MetaData object here
21 +# for 'autogenerate' support
22 +# from myapp import mymodel
23 +# target_metadata = mymodel.Base.metadata
24 +from flask import current_app
25 +config.set_main_option(
26 + 'sqlalchemy.url',
27 + str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%'))
28 +target_metadata = current_app.extensions['migrate'].db.metadata
29 +
30 +# other values from the config, defined by the needs of env.py,
31 +# can be acquired:
32 +# my_important_option = config.get_main_option("my_important_option")
33 +# ... etc.
34 +
35 +
36 +def run_migrations_offline():
37 + """Run migrations in 'offline' mode.
38 +
39 + This configures the context with just a URL
40 + and not an Engine, though an Engine is acceptable
41 + here as well. By skipping the Engine creation
42 + we don't even need a DBAPI to be available.
43 +
44 + Calls to context.execute() here emit the given string to the
45 + script output.
46 +
47 + """
48 + url = config.get_main_option("sqlalchemy.url")
49 + context.configure(
50 + url=url, target_metadata=target_metadata, literal_binds=True
51 + )
52 +
53 + with context.begin_transaction():
54 + context.run_migrations()
55 +
56 +
57 +def run_migrations_online():
58 + """Run migrations in 'online' mode.
59 +
60 + In this scenario we need to create an Engine
61 + and associate a connection with the context.
62 +
63 + """
64 +
65 + # this callback is used to prevent an auto-migration from being generated
66 + # when there are no changes to the schema
67 + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
68 + def process_revision_directives(context, revision, directives):
69 + if getattr(config.cmd_opts, 'autogenerate', False):
70 + script = directives[0]
71 + if script.upgrade_ops.is_empty():
72 + directives[:] = []
73 + logger.info('No changes in schema detected.')
74 +
75 + connectable = engine_from_config(
76 + config.get_section(config.config_ini_section),
77 + prefix='sqlalchemy.',
78 + poolclass=pool.NullPool,
79 + )
80 +
81 + with connectable.connect() as connection:
82 + context.configure(
83 + connection=connection,
84 + target_metadata=target_metadata,
85 + process_revision_directives=process_revision_directives,
86 + **current_app.extensions['migrate'].configure_args
87 + )
88 +
89 + with context.begin_transaction():
90 + context.run_migrations()
91 +
92 +
93 +if context.is_offline_mode():
94 + run_migrations_offline()
95 +else:
96 + run_migrations_online()
1 +"""${message}
2 +
3 +Revision ID: ${up_revision}
4 +Revises: ${down_revision | comma,n}
5 +Create Date: ${create_date}
6 +
7 +"""
8 +from alembic import op
9 +import sqlalchemy as sa
10 +${imports if imports else ""}
11 +
12 +# revision identifiers, used by Alembic.
13 +revision = ${repr(up_revision)}
14 +down_revision = ${repr(down_revision)}
15 +branch_labels = ${repr(branch_labels)}
16 +depends_on = ${repr(depends_on)}
17 +
18 +
19 +def upgrade():
20 + ${upgrades if upgrades else "pass"}
21 +
22 +
23 +def downgrade():
24 + ${downgrades if downgrades else "pass"}
1 +"""empty message
2 +
3 +Revision ID: 415b13ebc457
4 +Revises:
5 +Create Date: 2020-08-26 02:18:08.862101
6 +
7 +"""
8 +from alembic import op
9 +import sqlalchemy as sa
10 +
11 +
12 +# revision identifiers, used by Alembic.
13 +revision = '415b13ebc457'
14 +down_revision = None
15 +branch_labels = None
16 +depends_on = None
17 +
18 +
19 +def upgrade():
20 + # ### commands auto generated by Alembic - please adjust! ###
21 + op.create_table('article',
22 + sa.Column('id', sa.Integer(), nullable=False),
23 + sa.Column('subject', sa.String(length=200), nullable=False),
24 + sa.Column('content', sa.Text(), nullable=False),
25 + sa.Column('create_date', sa.DateTime(), nullable=False),
26 + sa.PrimaryKeyConstraint('id')
27 + )
28 + op.create_table('project',
29 + sa.Column('id', sa.Integer(), nullable=False),
30 + sa.Column('projectName', sa.String(length=200), nullable=False),
31 + sa.Column('projectType', sa.String(length=200), nullable=False),
32 + sa.Column('pictureName', sa.String(length=200), nullable=False),
33 + sa.Column('content', sa.Text(), nullable=False),
34 + sa.Column('gitAddress', sa.String(length=200), nullable=False),
35 + sa.Column('create_date', sa.DateTime(), nullable=False),
36 + sa.PrimaryKeyConstraint('id')
37 + )
38 + op.create_table('user',
39 + sa.Column('id', sa.Integer(), nullable=False),
40 + sa.Column('username', sa.String(length=150), nullable=False),
41 + sa.Column('password', sa.String(length=200), nullable=False),
42 + sa.Column('email', sa.String(length=120), nullable=False),
43 + sa.PrimaryKeyConstraint('id'),
44 + sa.UniqueConstraint('email'),
45 + sa.UniqueConstraint('username')
46 + )
47 + # ### end Alembic commands ###
48 +
49 +
50 +def downgrade():
51 + # ### commands auto generated by Alembic - please adjust! ###
52 + op.drop_table('user')
53 + op.drop_table('project')
54 + op.drop_table('article')
55 + # ### end Alembic commands ###
1 +"""empty message
2 +
3 +Revision ID: 47168028e699
4 +Revises: 8692d2d51066
5 +Create Date: 2020-08-31 05:13:48.638348
6 +
7 +"""
8 +from alembic import op
9 +import sqlalchemy as sa
10 +
11 +
12 +# revision identifiers, used by Alembic.
13 +revision = '47168028e699'
14 +down_revision = '8692d2d51066'
15 +branch_labels = None
16 +depends_on = None
17 +
18 +
19 +def upgrade():
20 + # ### commands auto generated by Alembic - please adjust! ###
21 + op.drop_table('article')
22 + # ### end Alembic commands ###
23 +
24 +
25 +def downgrade():
26 + # ### commands auto generated by Alembic - please adjust! ###
27 + op.create_table('article',
28 + sa.Column('id', sa.INTEGER(), nullable=False),
29 + sa.Column('subject', sa.VARCHAR(length=200), nullable=False),
30 + sa.Column('content', sa.TEXT(), nullable=False),
31 + sa.Column('create_date', sa.DATETIME(), nullable=False),
32 + sa.PrimaryKeyConstraint('id')
33 + )
34 + # ### end Alembic commands ###
1 +"""empty message
2 +
3 +Revision ID: 8692d2d51066
4 +Revises: 415b13ebc457
5 +Create Date: 2020-08-31 05:13:14.858317
6 +
7 +"""
8 +from alembic import op
9 +import sqlalchemy as sa
10 +
11 +
12 +# revision identifiers, used by Alembic.
13 +revision = '8692d2d51066'
14 +down_revision = '415b13ebc457'
15 +branch_labels = None
16 +depends_on = None
17 +
18 +
19 +def upgrade():
20 + # ### commands auto generated by Alembic - please adjust! ###
21 + op.drop_table('user')
22 + # ### end Alembic commands ###
23 +
24 +
25 +def downgrade():
26 + # ### commands auto generated by Alembic - please adjust! ###
27 + op.create_table('user',
28 + sa.Column('id', sa.INTEGER(), nullable=False),
29 + sa.Column('username', sa.VARCHAR(length=150), nullable=False),
30 + sa.Column('password', sa.VARCHAR(length=200), nullable=False),
31 + sa.Column('email', sa.VARCHAR(length=120), nullable=False),
32 + sa.PrimaryKeyConstraint('id'),
33 + sa.UniqueConstraint('email'),
34 + sa.UniqueConstraint('username')
35 + )
36 + # ### end Alembic commands ###